0

How can I know the name of the variable used within the ng-repeat directive?

I have two nested directives like this:

<div data-ng-list-item-multi ng-repeat="item in items | isArray">
  ...
</div>

Then, the directive needs to know how many elements exist inside that item variable (that is an array), but it is exposed through property named after the property I chose for in the ng-repeat clause:

.directive("ngListItemMulti", function(){
    return {
        restrict: 'AE',
        link: function(scope, element, attrs, controller) {
            var itemCount = scope.item.length;

            ...
        }
      };
})

The problem is that I choose to use ng-repeat="whatever in items" it will stop working, because then I should use scope.whatever.length.

Is there anyway to know the name of that selected variable?

Cheers.

UPDATE: The question is about how to know the name of the property ... but without indicating it somewhere else.

3 Answers 3

4

Create a two-way binding scope. You'll have to pass the variable name though.

<div data-ng-list-item-multi item-multi="item" ng-repeat="item in items | isArray">
  ...
</div>


.directive("ngListItemMulti", function(){
    return {
        restrict: 'AE',
        scope: {
            itemMulti: '='
        },
        link: function(scope, element, attrs, controller) {
            var itemCount = scope.itemMulti.length;

            ...
        }
      };
})
Sign up to request clarification or add additional context in comments.

3 Comments

actually you accidentally write item-multi="item" instead of item-multi="items" (s in the end). the item is not knows at this point but the items does.
Item is defined within the scope, it fires for each one in ng-repeat. My code is tested and works.
Oh sorry, I didn't see you are adding an attribute with the var name! In that case why do I need an isolated storage? I can do scope[attrs["item-multi"]], right? You are not finding out the name of the var, you are indicating it!
0

You can use what angular uses within the ngRepeat code. use:

var expression = $attr.ngRepeat; to get the expression

var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/) to break expression

var collection = match[2]; to get collection

$scope.$watchCollection(rhs, fn); to watch collection

Then in the watch function (fn) you can use you can use the collection.length; if you don't want to watch you can use $parse to get the value.

Comments

0

In order to solve your problem, what we want to be able to do is separate the scope inside a directive from the scope outside, and then map the outer scope to a directive's inner scope. This can be accomplished using an isolate scope. To do this, we will add a scope property to our directive object:

scope: {
  item: '=item'
}

Our full directive might now look something like this:

myApp.directive('listItemMulti', function($log) {
  return {
    restrict: 'E',
    link: function(scope, elem) {
        var length = scope.item.length;
        ...
    },
    scope: {
      item: '=item'
    }
  }
});

This can be used in our html like this:

<div ng-controller="SampleCtrl">
  <list-item-multi ng-repeat="whatever in items" item="whatever">
  </list-item-multi>
</div>

What we are doing here is designating a variable in our directive that we can bind to when we use our directive in our html. Here we've added the variable item. This can now be assigned to by using the variable name as an html attribute on our custom element. Notice how we've assigned whatever to the attribute item. Now, within our link function, our scope variable will contain the value that item was bound to. This allows us to designate specific variables that we want to be visible within out directive, but also provides an extra layer of indirection that prevents our code from being brittle. We can now change the name of the outside variable to whatever we feel like without needing to change anything within our directive.

Also, notice that I have renamed your directive to listItemMulti instead of ngListItemMulti. The ng prefix of directives is a convention specific to the built in angular directives. You should avoid using this prefix in your custom directives so that you can prevent any accidental naming conflicts that might occur. Often, it is best practice to give all your directives some standard prefix that relates to the name of the application. For instance, if I was developing an app for Stack Overflow, I might prefix all my directives with so.

Here is a plnkr with a working example: http://plnkr.co/edit/BdtWcuUz34GxhkrKWCwS?p=preview

The documentation on directives, and specifically isolate scope can be found here: https://docs.angularjs.org/guide/directive. (ctrl+f "Isolating the Scope of a Directive").

Hope this helps :-)

2 Comments

Thanks pje, but you are not finding out the name of the var, you are indicating it in that item="whatever"attribute. The idea is to find the name, without indicating it.
@vtortola I am not sure that there is a way to do what you are asking in AngularJS.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.