Angular does not update associated property
Fiddle
HTML:
<div ng-controller="MyCtrl">
<button my-event-directive>Click me</button>
<div>{{secret}}</div>
</div>
JS:
var myApp = angular.module('myApp',[]);
myApp.directive('myEventDirective', function() {
return {
link: function(scope, element) {
element.on('click', function(event){
scope.$emit('myEvent', {secret: 'aaa'});
});
}
}
})
function MyCtrl($scope) {
$scope.secret = 'bbb';
$scope.$on('myEvent', function(event, data){
alert('event received!');
$scope.secret = data.secret;
});
}
After pressing the button, the event is received in the controller (a warning appears). However, the binding {{secret}}
does not update its value. Why?
My event creation is more complicated in real code, of course.
As @Cherinv pointed out in a comment, when you change the outsite scope attributes to an Angular method, $apply
you have to call it manually. @runTarm also suggested that the event dispatcher should use $apply
because the listeners are freed from remembering it. So:
scope.$emit('myEvent', {secret: 'aaa'});
should be changed to:
scope.$apply(function() {
scope.$emit('myEvent', {secret: 'aaa'});
});
$apply
is detailed in the following article: http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
USE $ scope. $ apply (). NOW the changes will be noticed and the page will be updated.
var myApp = angular.module('myApp',[]);
myApp.directive('myEventDirective', function() {
return {
link: function(scope, element) {
element.on('click', function(event){
scope.$emit('myEvent', {secret: 'aaa'});
});
}
}
})
function MyCtrl($scope) {
$scope.secret = 'bbb';
$scope.$on('myEvent', function(event, data){
alert('event received! secret is ' + data.secret);
$scope.$apply(function () {
$scope.secret = data.secret;
});
});
}
You can try changing the binding to happen to object.value rather than value. Perhaps this is the case where angular is unable to track an immutable property change.
<div ng-controller="MyCtrl">
<button my-event-directive>Click me</button>
<div>{{data.secret}}</div>
</div>
var myApp = angular.module('myApp',[]);
myApp.directive('myEventDirective', function() {
return {
link: function(scope, element) {
element.on('click', function(event){
scope.$emit('myEvent', {secret: 'aaa'});
});
}
}
})
function MyCtrl($scope) {
$scope.data = {
secret: 'bbb'
};
$scope.$on('myEvent', function(event, data){
alert('event received!');
$scope.data.secret = data.secret;
});
}
This should work.
PS since you always see the callable message, which means you don't need to call the scope. $ apply to call scope and assigned value digests, problem is angular can't look at immutable values (maybe)