Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In AngularJS, how to make an isolated scope inherit from ng-repeat's scope

I'm trying to create a custom component that receives arguments in a ng-repeat loop. So for example, say I have a component named "mycomp" that receives a custom argument "name" in a ng-repeat:

<mycomp name="{obj.name}" ng-repeat="obj in list" />

And in my directive the isolated scope is defined like this:

scope:{name:"@"}

That won't work because ng-repeat creates an isolated scope for each element it iterates. So I ended up having two levels of scopes.

How do I get around this issue? Am I doing something wrong?

Thanks.

like image 450
yohairosen Avatar asked Nov 19 '12 08:11

yohairosen


1 Answers

As I stated in my comment of your original question, this has already been answered. Anyway, here it is, summed up:

In your template, state the model you want to have inherited, without {{}} (as using brackets results in the value being passed, and not the reference to the model itself):

<mycomp name="obj.name" ng-repeat="obj in list" />

And in your directive, establish a 2-way binding, like so:

scope:{name:"="}

EDIT:

I realize now (after your comment) that while this solves your problem, it doesn't fully answer the question. Here goes:

When you create a directive you have the choice of creating a scope that inherits from its parent (controller, typically, though not necessarily) ou an "isolated" scope, by specifying scope: true or scope: {...}, respectively.

So, by creating an unisolated scope, all the parent's models are available (you can access scope.obj - created via ng-repeat - but also scope.list). This is convenient, but also dangerous, of course (and doesn't really create reusable code).

If you create an isolated scope, you can specify the scope's models using '@', '=' or '&'.

'@' and '&' both produce a isolated, unbinded value, (that, if you change, changes only on the isolated scope - in your case, the object in the original list suffers no change at all), the only difference being that '@' reads a string value, and '&' reads an expression. THIS IS IMPORTANT: the reason why I believe your code didn't work was (only) because you passed name="{obj.name}" and not name="{{obj.name}}", for with '@' the string value is read, and that string value can be the name of obj, but you must include it in {{}}!

If you use '=', you are declaring that you want that variable to be binded with the specified outside variable. So, if (in a fit of crazy, crazy rage!) you want to have 2 models in your directive that start up with the same value, but on is binded (i.e. changes are propagated to the outside scope), you could do something like this:

<mycomp binded-name="obj.name" unbinded-name="{{obj.name}}" ng-repeat="obj in list" />

and in your directive:

scope:{
  bindedName: "=",
  unbindedName: "@"
}
like image 169
Tiago Roldão Avatar answered Oct 05 '22 16:10

Tiago Roldão