fionsay fionsay - 5 months ago 15
Javascript Question

Why are changes done to $scope in directive's link function not reflected on UI?

AngularJS directives'

link
function change isolate scope data not reflected in UI.

Here is an example:

var myApp = angular.module('myApp', []);

myApp.directive('myDirective', function () {
return {
restrict: 'A',
template: '<span>Title: {{myParams.title}}</span>',
scope: {
myParams: '='
},
link: function ($scope) {
// the new value is not reflected in ui
$scope.myParams.title = 'this is myDirective';
}
};
});


HTML:

<div my-directive my-params="{title: 'this is title'}"></div>


I want the HTML page to display
this is myDirective
but in fact it is
this is title
.

In addition, could you explain why it is displaying like this. Thanks

Answer

The reason is that the my-params="{title: 'this is title'}" is a constant expression and not assignable. So even though you try to overwrite the 'title' property, it gets overwritten back from the constant. Check this fiddle. It contains your code and is set to work with Angular 1.4. With the difference that the directive is used once as above and once with a changable, non-constant value from a controller:

<div ng-app="app" ng-controller="Ctrl as ctrl">
  <div my-directive my-params="{title: 'this is title'}"></div>
  <div my-directive my-params="data"></div>
</div>

The second instance (non-constant expression) works.

Now try to change the Angular version to 1.2. Notice that now Angular throws an infinite digest error:

VM1033 angular.js:9101 Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["fn: parentValueWatch; newVal: {\"title\":\"this is title\"}; oldVal: {\"title\":\"this is title\"}"],["fn: parentValueWatch; newVal: {\"title\":\"this is title\"}; oldVal: {\"title\":\"this is title\"}"],["fn: parentValueWatch; newVal: {\"title\":\"this is title\"}; oldVal: {\"title\":\"this is title\"}"],["fn: parentValueWatch; newVal: {\"title\":\"this is title\"}; oldVal: {\"title\":\"this is title\"}"],["fn: parentValueWatch; newVal: {\"title\":\"this is title\"}; oldVal: {\"title\":\"this is title\"}"]]

The expression given in the directive (i.e. my-params="{title: 'this is title'}") is trying to overwrite the directive scope attribute (always creating a new object in 1.2, hence the infinite digest).