Can I avoid the object variable name in ng-repeat

2019-03-29 04:06发布

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

2条回答
萌系小妹纸
2楼-- · 2019-03-29 04:39

It all depends on how you structure your directive. It's hard to tell without a fiddle/plunkr what your code looks like so I'm taking a stab in the dark here. Right now I think what you're trying to say is that in the context of where you're using your directive friend.name does not make sense. Perhaps something more generic like person.name might be more appropriate. In that case you can do the following so that you pass in to the directive what you want the person to be associated with:

Html

<div data-ng-repeat="friend in friends">
    {{ friend.name }}
    <div class="myDirective" data-person="friend"></div>
</div>

javascript

.directive("myDirective", function(){
    return {
        restrict: 'C',
        scope: {
            person: "=person"
        },
        template: "<div>{{ person.name }}</div>"

    }
});

jsfiddle: http://jsfiddle.net/5aVLf/1/

查看更多
在下西门庆
3楼-- · 2019-03-29 04:45

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!

查看更多
登录 后发表回答