The question: Is there a way to get the desired model change without injecting $scope into an Angular "controller as" method in the following set up?
The 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>
The controller:
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);
};
}
]);
The explanation: I fetch an array of buildings from a service, and then set the first one as a default into the scope. Then I calculate (using latitudes, and longitudes of the buildings) which of the buildings is the closest one to my current location, and change the model object accordingly.
This all works. The default building flashes in the first html select control, which then changes into the nearest building.
However, I find it awkward having to inject $scope into the controller, when I'm using the "Controller as" syntax, because usually that is not needed. You see, if I take out the $scope.$apply(); line, the view does not change. It still shows the default building, even though the vm.selected.building actually contains the closest one. (And when I try to select a room from the second html select, the first one updates to the value actually in the vm.selected.building model object.
So, why is this? Is there a way to get the desired functionality without the injection?
EDIT: So the real question is: Why do I have to call $scope.$apply() here? Why does the view not change without it?