Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does assignment not always work in Angular expressions?

I just found this interesting apparent inconsistency in what is allowed in Angular expressions:

  1. It is possible to perform assignment in an expression
  2. This breaks if the assignment involves a local variable from an ngRepeat
  3. This can be overcome by using a setter defined in the controller instead of assignment in the expression

See Plunker

The docs on expressions seem only to explicitly disallow control flow in expressions, and I don't see any mention of the kind of behavior above.

I suppose the takeaway from this is it's probably a better design pattern to use a setter anyway, but does anyone know of a more definitive reference on what's possible in expressions?

Maybe it would be better if Angular unilaterally prohibited assignment in them. (A related inconsistency is that it seems to be possible to increment in an expression with i = i+1 but not with i+=1...)

like image 341
bellkev Avatar asked Feb 23 '13 06:02

bellkev


1 Answers

It is a known problem with scoping in directives. You can read the article The Nuances of Scope Prototypal Inheritance to know more about the scoping in angular js.

Any primitive value assignment from a child/transcluded scope will create a new instance value instead of changing the parent scopes value

In your case you are working with a primitive value selectedNumber.

There are two suggested ways to fix it

Solution 1
Use a object instead of primitive value.

  1. Change selectedNumber to an object scope.selectedNumber = { num : 1 };
  2. Change display to <h2>{{ selectedNumber.num }}</h2>
  3. Change the click handler in ng-repeat to ng-click="selectedNumber.num = number"

Demo: Plunker

Solution 2:
Use $parent scope reference

  1. Change the click handler in ng-repeat to ng-click="$parent.selectedNumber = number"

Demo: Plunker

Solution 3:
Use a setter in the parent scope

  1. Create a setter method in the parent scope like $scope.setSelectedNumber = function(num){ $scope.selectedNumber = num}
  2. Change the click event to setSelectedNumber(number) (This is the method already used)

Update:
As suggested by Anders Ekdahl, it is advisable to use the object (solution 1) based solution.

like image 200
Arun P Johny Avatar answered Nov 15 '22 01:11

Arun P Johny