Why can't I rewrite the value of a variable like this?

I am trying to understand why I am unable to overwrite the value passed to the angularJS directive through the selection area ( @ ). I am trying to overwrite the value of vm.index as follows:

vm.index = parseInt(vm.index, 10)

However, for some reason this does not work.

If I changed it to:

vm.newIndex = parseInt(vm.index, 10)

It works. Also assigned a value in $scope .

Why does the first method not work?

I created this plunker example for reference.

+7
javascript angularjs angularjs-scope angularjs-directive angularjs-controlleras
source share
2 answers

As you used @ here, where the value from the attribute with the {{}} interpolation directive is required. And it looks like the directive is loaded first, and then the vm.index value is vm.index . Thus, changes do not occur in the current digest cycle. If you want them to be reflected, you need to start the digest cycle in a more secure way using $ timeout.

 $timeout(function(){ vm.index = parseInt(vm.index, 10) }) 

First of all, this means that the value is converted to a decimal value. Adding will be performed in the html directive <h2>Item {{ vm.index + 1 }}</h2>

Working demo

Possible reason for this

According to @dsfq and my discussion, we went through the angular $compile API and found that their one method calls initializeDirectiveBindings , which only gets called when we use controllerAs in an isolated volume directive. In this function, there are switching cases for various @ , = and & bindings, since you use @ , which means that a one-way binding is called after the switch code code.

the code

 case '@': if (!optional && !hasOwnProperty.call(attrs, attrName)) { destination[scopeName] = attrs[attrName] = void 0; } attrs.$observe(attrName, function(value) { if (isString(value)) { destination[scopeName] = value; } }); attrs.$$observers[attrName].$$scope = scope; if (isString(attrs[attrName])) { // If the attribute has been provided then we trigger an interpolation to ensure // the value is there for use in the link fn destination[scopeName] = $interpolate(attrs[attrName])(scope); } break; 

In the above code, you can see that they put attrs.$observe , which is one type of observer that is usually used when the value has interpolation, for example, in our case it’s the same {{index}} , it means that this $observe gets evaluated when the digest cycle starts, so you need to put $timeout when creating the index value as decimal .

The reason for @dsfq's answer works because it uses = , provides a two-way binding, the code of which does not put the observer directly from the value of the selected area, here is the code . Thus, without a loop, the digest whose value is updated.

+7
source share

Apparently, this has something to do with the one-way binding of the value of the index . This way Angular will not update scope.index (or this.index in case of bindToController: true ), because the configuration area is configured as

 scope: { index: '@' }, 

If you change it to two-way binding, for example:

 scope: { index: '=' }, 

It will work:

 <some-directive index="$index"></some-directive> 

Demo: http://plnkr.co/edit/kq16cpk7gyw8IE7HiaQL?p=preview

UPD . @pankajparkar made a good point that updating the value in the next digest fixed the problem. Then this approach to the problem is closer than what I did in this answer.

+6
source share

All Articles