没有$ scope,模型不会改变。$ apply

时间:2014-09-27 08:29:52

标签: javascript angularjs

问题:如果没有将$ scope注入到以下设置中的Angular“controller as”方法中,是否有办法获得所需的模型更改?

html:

<div data-ng-controller="Buildings as vm">
  <select data-ng-model="vm.selected.building"
          data-ng-options="building.name for building in vm.buildings"
          data-ng-change="vm.changeBuilding()">
  </select>
  <div data-ng-repeat="building in vm.buildings">
    <div data-ng-if="vm.selected.building.name === building.name">
      <select data-ng-model="vm.selected.room"
              data-ng-options="room.name for room in building.rooms"
              data-ng-change="vm.changeRoom()">
        <option value=""></option>
      </select>
    </div>
  </div>
</div>

控制器:

angular.module('App').controller('Buildings', ['$scope', 'BuildingService', 'Geolocation',
    function ($scope, BuildingService, Geolocation) {
        var vm = this;
        BuildingService.getAll().then(function (buildings) {
            vm.buildings = buildings;
            vm.selected = { // defaults
                building: buildings[0],
                room: null
            };
        });
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(function (position) {
                vm.selected.building = Geolocation.closest(position, vm.buildings);
                vm.selected.room = null;
                $scope.$apply(); // <--- Why is that needed?
            });
        }
        vm.changeBuilding = function () {
            vm.selected.room = null;
            console.log(vm.selected);
        };
        vm.changeRoom = function () {
            console.log(vm.selected);
        };
    }
]);

解释:我从服务中获取建筑物阵列,然后将第一个建筑物作为默认设置放入范围。然后我计算(使用建筑物的纬度和经度)哪个建筑物最接近我当前的位置,并相应地更改模型对象。

这一切都有效。默认建筑在第一个html选择控件中闪烁,然后更改为最近的建筑物。

但是,当我使用“Controller as”语法时,我发现将$ scope注入控制器很麻烦,因为通常不需要。你看,如果我拿出$ scope。$ apply();行,视图不会改变。它仍显示默认构建,即使vm.selected.building实际上包含最接近的构建。 (当我尝试从第二个html选择中选择一个房间时,第一个更新为vm.selected.building模型对象中的实际值。

那么,为什么呢?有没有办法在没有注射的情况下获得所需的功能?

编辑:所以真正的问题是:为什么我必须在这里调用$ scope。$ apply()?如果没有它,为什么视图不会改变?

1 个答案:

答案 0 :(得分:1)

在本节中,您将在回调中更新vm.selected.building

        navigator.geolocation.getCurrentPosition(function (position) {
            /* See how this is a callback passed to getCurrentPosition that will be executed later */
            vm.selected.building = Geolocation.closest(position, vm.buildings);
            vm.selected.room = null;
            $scope.$apply(); // <--- Why is that needed?
        });

在apply()期间,angular会同步绑定。大多数操作应用后自动调用,例如在构造函数代码之后或在您提供给角度代码的大多数回调之后。但是,如果您的第三方图书馆没有自动为您申请$申请,您需要自己这样做。所以你要么必须注入范围以便你可以在这里申请,或者你需要使你的navigator(这似乎是一个全局变量)成为一个有角度的服务,并让这一个电话适用于你。