undefined - AngularJS directive with ng-repeat not redering -
the problem have manage list of gum balls retrieved service. directive i've created seems work when hardcode elements in html, when attempt dynamically allocate gum balls using ng-repeat.
html
<div ng-controller="gumballsctrl"> <h1>working</h1> <ul> <li ng-repeat="gumball in gumballs"> <div class="gumballcolor{{gumball.color}}">{{gumball.color}}</div> </li> </ul> <h1>problem - expecting same result @ work version</h1> <ul> <li ng-repeat="gumball in gumballs"> <mygumball id={{gumball.id}} color="{{gumball.color}}">{{gumball.color}}</mygumball> </li> </ul> </div>
javascript
var myapp = angular.module('myapp', []); function gumballsctrl($scope, gumballs) { $scope.gumballs = gumballs; } myapp.factory('gumballs', function () { return [{ id: '1', color: 'r' }, { id: '2', color: 'g' }, { id: '3', color: 'b' }, { id: '4', color: 'y' }, { id: '5', color: 'g' }]; }); myapp.directive('mygumball', function ($scope) { return { restrict: 'e', scope: {}, link: function (scope, element, attrs) { if (attrs.color !== '' && attrs.color !== undefined) { scope.color = attrs.color; } else { scope.color = 'u'; } }, replace: true, template: "<div class='gumballcolor{{color}}'>{{color}}</div>" }; });
css
.gumballcolorr { font-size: 12px; text-align: center; padding: 2px; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; border: solid 1px #cc0000; background-color: #ff0000; width: 15px; height: 15px; margin-left: 5px; margin-top: 5px; } .gumballcolorg { font-size: 12px; text-align: center; padding: 2px; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; border: solid 1px #00cc00; background-color: #00ff00; width: 15px; height: 15px; margin-left: 5px; margin-top: 5px; } .gumballcolorb { font-size: 12px; text-align: center; padding: 2px; color: #ffffff; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; border: solid 1px #0000cc; background-color: #0000ff; width: 15px; height: 15px; margin-left: 5px; margin-top: 5px; } .gumballcolory { font-size: 12px; text-align: center; padding: 2px; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; border: solid 1px #cccc00; background-color: #ffff00; width: 15px; height: 15px; margin-left: 5px; margin-top: 5px; } .gumballcoloru { font-size: 12px; text-align: center; padding: 2px; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; border: solid 1px #cccccc; background-color: #dddddd; width: 15px; height: 15px; margin-left: 5px; margin-top: 5px; }
http://jsfiddle.net/i3sik/ngb9v/22/
the id , color attributes when passed directive end being undefined when passed using ng-repeat, work when hardcoded in html.
thank can provide.
the problem here isolate scope. using scope: {}
created new, isolate scope act on element. isolate scopes don't inherit parent scope. attributes , content on directives isolate scopes evaluated within context of isolate scope. gumball
doesn't exist in isolate scope, comes undefined.
you have 2 choices fix this: (1) remove isolate scope (e.g. scope: true
create child scope); or (2) bind values in isolate scope.
to bind attributes scope variables, need specify scope , kind of binding want:
scope: { id: '@', color: '@' },
this says attributes id
, color
interpolated in context of parent scope , added scope. can remove logic inside link
function - you.
but still leaves problem of content inside directive. interpolate in context of parent scope, need transclusion:
transclude: true, template: "<div class='gumballcolor{{color}}' ng-transclude></div>"
transclusion takes contents of element , interpolates relative new child of parent scope, e.g. gumball
still defined.
with these 2 changes, directive work desired.
if you're confused scope use, here's question might help: when writing directive, how decide if need no new scope, new child scope, or new isolate scope?
side note: without isolate scope, logic in link
function determine attribute values wouldn't work. order of execution important part here, roughly: compiler -> controller -> link -> interpolation. until interpolation done, there no value attributes. checks won't work.
that said, can set $observe
on interpolated attributes; $observe
fire first time, if there no value passed. can use set default. $observe
efficient.
attrs.$observe( 'attr1', function(val) { if ( !angular.isdefined( val ) ) { scope.attr1 = 'defaultvalue'; } });
Comments
Post a Comment