AngularJS directive with ng-repeat not rendering AngularJS directive with ng-repeat not rendering angularjs angularjs

AngularJS directive with ng-repeat not rendering


The problem here is your isolate scope. By using scope: {} you created a new, isolate scope to act on that element. Isolate scopes don't inherit from the parent scope. All attributes and content on directives with isolate scopes are evaluated within the context of the isolate scope. gumball doesn't exist in the isolate scope, so everything comes up as undefined.

You have two choices to fix this: (1) remove the isolate scope (e.g. scope: true to create a child scope); or (2) bind the values in your isolate scope.

To bind your attributes to scope variables, you simply need to specify the scope and the kind of binding you want:

scope: {  id: '@',  color: '@'},

This says that the attributes id and color are to be interpolated in the context of the parent scope and then added to the scope. You can remove all that logic inside your link function - this will do it for you.

But this still leaves the problem of the content inside the directive. To interpolate that in the context of the parent scope, you need transclusion:

transclude: true,template: "<div class='gumballColor{{color}}' ng-transclude></div>"

Transclusion takes the contents of the element and interpolates relative to a new child of the parent scope, e.g. where gumball would still be defined.

With these two changes, your directive will work as desired.

If you're confused about which scope to use, here's another SO question that might help: When writing a directive, how do I decide if a need no new scope, a new child scope, or a new isolate scope?


Side note: Even without the isolate scope, the logic in your link function to determine attribute values wouldn't work. Order of execution is the important part here, which is roughly: compiler -> controller -> link -> interpolation. Until the interpolation is done, there is no value for your attributes. So your checks won't work.

That said, you can set up an $observe on interpolated attributes; the $observe will always fire the first time, even if there was no value passed. You can use this to set your default. $observe is also very efficient.

attrs.$observe( 'attr1', function(val) {  if ( !angular.isDefined( val ) ) {    scope.attr1 = 'defaultValue';  }});