0

I have a very simple directive that does not have an isolate scope. It's being used on a ng-repeat element and I want to limit which element out of that ng-repeat it works on. It doesn't work on every element created by the ng-repeat. So I have an attribute that evaluates an angular expression within the scope, but it appears that it's not working. I have a feeling this is because ng-repeat creates its own scope, but I think I don't have access to it. Here is the directive code:

App.directive('testDriveStep', ['$log', function($log) {
  return {
    link: function( $scope, element, attribs ) {
        // this is the line that has trouble.
        var enabled = attribs.testDriveEnabled ? $scope.$eval(attribs.testDriveEnabled) : true;
        if( enabled ) {
           // enable the directive otherwise do nothing
        }
    }
  };
}]);

Here is my code I'm trying to execute:

<li ng-repeat="item in items" test-drive-step test-drive-enabled="$index == 0 && item.band == 'band1'"/>

If I remove the second part of the boolean expression in enabled attribute (ie lesson.band == 'band1'). It works in that the evaluation evaluates correctly. However, when I add the use of item it seems like item is undefined which makes me think the scope of directive isn't the same as ng-repeat. What do I need to do to fix this?

chubbsondubs
  • 37,646
  • 24
  • 106
  • 138

1 Answers1

0

You'll need to make the directive isolated scope, and have test-drive-enabled be in that defined scope:

return {
    scope: {
      testDriveEnabled: '='
    },
    link: function(scope, element, attr) {
      // access expression with scope.testDriveEnabled
    }

It can't be shared scope, because the directive is applied to each ng-repeat element. Since you want to have multiple instances at once, you'll need isolated scope.

Also, consider passing along a function instead of an expression -- like

<li ng-repeat="item in items" test-drive-enabled="isTestDriveEnabled($index, item)"></li>

And in your controller, define:

scope.isTestDriveEnabled = function(idx, item) {
  return (idx === 0 || item.band === 'band1');
}

You could also just send $index and item to the directive (as isolated scope vars), then have the logic live within the directive. That'll keep all directive logic in the directive, which'd make this directive more reusable.

Ghan
  • 797
  • 8
  • 28
  • I'm not sure this really explains why what I did doesn't work. Each instance is separated through the use of attributes. The scope isn't isolated, but that presents other problems to use isolate scope. Consider this. Whatever '=' isolate scope is doing under the hood is what I'm looking for. I thought that was $scope.$eval(), but that is what I'm doing. So somehow I'm not doing the same thing that '=' does. What is that? – chubbsondubs Dec 08 '14 at 18:03
  • Take a look at this plunk: http://plnkr.co/edit/B4OSHtgZh4ZcAiMmhOkM?p=preview -- shows that attributes with eval isn't enough to create instances. I'm working on a more thorough explanation. – Ghan Dec 08 '14 at 18:21
  • Hey again -- take a look at this response: http://stackoverflow.com/a/14914798/1220172 -- you can use child scope for the directive (set scope: true), then you can use attributes to send different data to the directive. If isolated scope will cause trouble for you, maybe this is the best solution? – Ghan Dec 08 '14 at 18:32
  • Your plnkr makes a crucial mistake that my code doesn't. You store your $scope.$eval() result to $scope which in that case YES isolated scopes make a difference. I'm not doing that. I'm storing it to a local variable so it would be different results, and that actually proves out in my tests. Not every item of the ng-repeat has enabled the directive. – chubbsondubs Dec 08 '14 at 22:20