Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I avoid the object variable name in ng-repeat loop?

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

like image 211
OpherV Avatar asked Apr 04 '13 12:04

OpherV


People also ask

What can I use instead of NG-repeat?

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.

Does ng-repeat create a new scope?

However, some directives, such as ng-controller and ng-repeat, create new child scopes and attach the child scope to the corresponding DOM element.

What does ng-repeat do?

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.

How do you pass an index in NG-repeat?

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.


1 Answers

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!

like image 161
OpherV Avatar answered Oct 12 '22 23:10

OpherV