When defining an ng-repeat directive to iterate over an array, the syntax specifies ng-repeat="friend in friends"
, and then within the template you use the interoplation operator like so {{friend.name}}
.
Is it possible to have the properties assigned to the current item scope, rather than a variable in it? So I could call just {{name}}
instead of {{friend.name}}
?
The reason being is that my directive is being used in the scope of two different templates - for example I might have a directive "userActions"
that is used in both a repeater, and also inside an unrelated template where {{friend.name}}
doesn't make sense. I would like to avoid artificially manufacturing the friend
object where it doesn't have a semantic meaning.
My use case is something like this:
I have a grid that renders blocks of various types. Some psuedo code:
<div ng-repeat="block in blocks">
< cat block />
< friend block >
<userActions directive />
</ friend block >
< guitar block />
.... more blocks
</div>
I also have a friend page, that contains the exact same user actions:
..fragment of friend page..
<element ng-control="friend">
<userActions directive />
</element>
Now, if I want to user a property of the block inside the repeater, the syntax is {{block.name}}
. So the template for userActions
contains this.
However, once I use this template in the friend page, I must create {{block.name}}
inside the scope of the friend controller. This does not make sense though, because the block only exists in the context of the block grid. I shouldn't have to create this block
.
What I want to be able to do, is just to call {{name}}
from within the userActions
directive template, since both the block scope and the controller contain it. I don't want to create a block
object, then artificially set block.name
in each scope where I want to use the userActions
directive.
Here's a jsFiddle to illustrate the cause
And you should consider using ng-repeat with pagination. You can consider using transclusion inside a custom directive, to achieve the behavior you are looking for without using ng-repeat.
However, some directives, such as ng-controller and ng-repeat, create new child scopes and attach the child scope to the corresponding DOM element.
The ng-repeat directive repeats a set of HTML, a given number of times. The set of HTML will be repeated once per item in a collection. The collection must be an array or an object. Note: Each instance of the repetition is given its own scope, which consist of the current item.
Each ng-repeat creates a child scope with the passed data, and also adds an additional $index variable in that scope. So what you need to do is reach up to the parent scope, and use that $index . Save this answer.
I've decided to combine the informative answers of Mathew Berg and ganaraj with my newfound knowledge to create a helpful answer to this.
The short answer is You really don't want to do that.
The longer answer is this:
When using ng-repeat="block in blocks
" , a new scope is created for each block element, and the properties of every block object are create in scope.block
of each block. This is a good thing, because this means all properties can be accessed by reference, updated or $watched.
If ng-repeat
wouldn't have done that, and all properties would just be slapped unto the block's scope, then all primitives in block
(strings, ints, etc) would just be copied from the block object to the block scope object. A change in one will not reflect on the other, and that's bad. More info on that here.
Ok so now that we've decided that's a good thing rather than a bad thing, how do we overcome the semantic issue? I've decided to use the friendData
object container as the object on the scope of my directive, and so the directive expects the friend-data
attribute to hold the relevant properties
angular.module('myApp',[])
.directive("lookActions", function(){
return {
restrict: 'E',
template: "<input value='Kill -{{ friendData.name }}-' type='button'>",
scope : {
friendData : '='
}
}
});
This way I can assign this object regardless of which context I'm calling my directive template.
Given these controller contexts:
function gridCtrl($scope) {
$scope.blocks = [{ type: "cat", name: "mitzi"},{ type: "friend", name: "dave"},{ type: "guitar", name: "parker"}];
}
function friendCtrl($scope) {
$scope.data={
name: "dave"
}
}
How to call the directive -
Within an ng-repeat
:
<div class="block" ng-repeat="block in blocks" >
<look-actions friend-data="block" />
</div>
Or in a difference context:
<div ng-controller="friendCtrl">
<look-actions friend-data="data" />
</div>
Here's the solution Fiddle
Thanks for all the help!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With