2013-04-05 9 views
7

Problem polega na tym, że muszę zarządzać listą kulek gumy, która jest pobierana z usługi. Wytworzona przeze mnie dyrektywa wydaje się działać, gdy koduję elementy w kodzie HTML, ale kiedy próbuję dynamicznie przydzielać kule gumy za pomocą powtórzenia ng.Dyrektywa AngularJS z ng-repeat not redering

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 the same result at the 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/

id i kolor atrybuty kiedy przeszedł do directi ve staje się niezdefiniowany, gdy jest przekazywany za pomocą ng-repeat, ale działa, gdy jest zakodowany na stałe w kodzie HTML.

Dziękuję bardzo za pomoc, którą możesz zapewnić.

Odpowiedz

10

Problem w tym przypadku dotyczy zakresu izolowania. Używając scope: {} utworzyłeś nowy, wyizoluj zakres, aby działać na tym elemencie. Zakresy izolowania nie dziedziczą z zakresu nadrzędnego. Wszystkie atrybuty i zawartość w dyrektywach z zakresami izolatów są oceniane w kontekście zakresu izolatu. gumball nie istnieje w zakresie izolowania, więc wszystko pojawia się jako niezdefiniowane.

Masz dwie opcje, aby to naprawić: (1) usuń zakres izolatu (np. scope: true, aby utworzyć zakres podrzędny); lub (2) wiążą wartości w swoim zakresie izolatu.

powiązać atrybuty zmiennych zakresie, wystarczy, aby określić zakres i rodzaj wiązania chcesz:

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

Ten mówi, że atrybuty id i color mają być interpolowane w kontekście zakres nadrzędny, a następnie dodany do zakresu. Możesz usunąć całą logikę wewnątrz swojej funkcji link - zrobi to za Ciebie.

Ale to nadal pozostawia problem z treścią w dyrektywie. Interpolacji, że w kontekście zakresu nadrzędnego, trzeba transkluzja:

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

dołączony zaczyna zawartość elementu i interpoluje w stosunku do nowego dziecka zakresu nadrzędnego, np gdzie nadal byłby zdefiniowany gumball.

Po wprowadzeniu tych dwóch zmian dyrektywa będzie działać zgodnie z oczekiwaniami.

Jeśli jesteś mylić o których zakres korzystania, oto kolejny SO pytanie, które mogą pomóc: When writing a directive, how do I decide if a need no new scope, a new child scope, or a new isolate scope?


Notatka: Nawet bez zakresie izolowania, logika w funkcji link do określenia wartości atrybutów nie będą działać. Kolejność wykonania to tutaj ważna część, czyli w przybliżeniu: kompilator -> kontroler -> link -> interpolacja. Dopóki interpolacja nie zostanie wykonana, nie ma żadnej wartości dla twoich atrybutów. Więc twoje czeki nie będą działać.

Powiedziawszy, możesz ustawić $observe na atrybutach interpolowanych; $observe zawsze będzie strzelać za pierwszym razem, nawet jeśli nie ma wartości przekazanej. Możesz użyć tego do ustawienia domyślnego. $observe jest również bardzo wydajny.

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

+1 dla sztuczki z wartością domyślną $ obser. –

Powiązane problemy