Angular does not update associated property
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.
source to share
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
source to share
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;
});
});
}
source to share
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)
source to share