I have the following code:
var testApp = angular.module('testApp', []);
testApp.directive('myDirective', function () {
return {
scope: {
child: '=child'
},
controller: function ($scope, $element, $attrs) {
$scope.$on('childChanged', function (event, newChild) {
if ($scope.child.id != newChild.id) {
alert("The child in the isolated scope is not updated!");
}
else {
alert("success");
}
});
}
};
});
testApp.controller('myController', function ($scope) {
$scope.parentObject = {childObject: {id:1}};
$scope.changeChild = function changeChild()
{
var newChild = { id: $scope.parentObject.childObject.id + 1};
$scope.parentObject.childObject = newChild;
//$scope.$apply(); //This solves the problem
$scope.$broadcast('childChanged', newChild);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app="testApp">
<div data-ng-controller="myController">
<div my-directive child="parentObject.childObject"></div>
<button data-ng-click="changeChild()">Change Child</button>
</div>
</div>
Explanation:
- I am creating an isolated scope for the directive, with a two-way binding to an object (parentObject.childObject) of the parent scope.
- When clicking on the button, the function changeChild is invoked in myController. This function will replace $scope.parentObject.childObject with another child, and will broadcast an event.
- The listener to this event is in the directive's controller. In the listener, we check whether the child in the isolated scope ($scope.child) is the same one as the one sent in the event (i.e. parent's scope.parentObject.childObject). We see that they are not the same, meaning the child we received in the isolated scope is not yet updated.
Please note that if I use $scope.$apply() before the broadcast, then $scope.child in the directive's controller will be updated, however, it will throw the following exception: "$apply already in progress".
Can someone please help me understand what is happening here? Why did the $scope.$apply help even though it only threw an excpetion? How this can be resolved without calling to $scope.$apply? I would like to know if there is a way to ensure that the bound property in the isolated scope gets updated once it is changed in the parent's scope, without the need to pass it in the event.
Thank you