Mam dyrektywę z izolowanym zakresem (aby móc ponownie wykorzystać dyrektywę w innych miejscach), a kiedy używam tej dyrektywy z rozszerzeniem ng-repeat
, nie działa.
Przeczytałem całą dokumentację i odpowiedzi Stack Overflow na ten temat i rozumiem problemy. Myślę, że uniknąłem wszystkich typowych problemów.
Rozumiem więc, że mój kod nie działa z powodu zakresu utworzonego przez ng-repeat
dyrektywę. Moja własna dyrektywa tworzy zakres izolowany i tworzy dwukierunkowe powiązanie danych z obiektem w zakresie nadrzędnym. Moja dyrektywa przypisze nową wartość obiektu do tej zmiennej związanej i działa to doskonale, gdy moja dyrektywa jest używana bez ng-repeat
(zmienna nadrzędna jest poprawnie aktualizowana). Jednak w ng-repeat
przypadku przypisanie tworzy nową zmienną w ng-repeat
zakresie, a zmienna nadrzędna nie widzi zmiany. Wszystko to jest zgodne z oczekiwaniami na podstawie tego, co przeczytałem.
Przeczytałem również, że gdy na danym elemencie jest wiele dyrektyw, tworzony jest tylko jeden zakres. I że priority
można ustawić w każdej dyrektywie, aby określić kolejność, w jakiej dyrektywy są stosowane; dyrektywy są sortowane według priorytetów, a następnie wywoływane są ich funkcje kompilujące (szukaj słowa „priorytet” na http://docs.angularjs.org/guide/directive ).
Miałem więc nadzieję, że mógłbym użyć priorytetu, aby upewnić się, że moja dyrektywa działa jako pierwsza i ostatecznie tworzy zakres izolowany, a po ng-repeat
uruchomieniu ponownie wykorzystuje zakres izolowany zamiast tworzyć zakres, który prototypowo dziedziczy z zakresu nadrzędnego. Z ng-repeat
dokumentacji wynika, że ta dyrektywa ma charakter priorytetowy 1000
. Nie jest jasne, czy 1
jest to wyższy poziom priorytetu, czy niższy poziom priorytetu. Kiedy użyłem poziomu priorytetu 1
w mojej dyrektywie, nie miało to znaczenia, więc spróbowałem 2000
. Ale to pogarsza sytuację: moje dwukierunkowe wiązania stają się, undefined
a moja dyrektywa nic nie wyświetla.
Stworzyłem skrzypce, aby pokazać mój problem . Skomentowałem priority
ustawienie w mojej dyrektywie. Mam listę obiektów nazw i dyrektywę o nazwie, name-row
która pokazuje pola imienia i nazwiska w obiekcie nazwy. Po kliknięciu wyświetlanej nazwy chcę, aby ustawiała selected
zmienną w głównym zakresie. Tablica nazw, selected
zmienna jest przekazywana do name-row
dyrektywy przy użyciu dwukierunkowego wiązania danych.
Wiem, jak to działa, wywołując funkcje w głównym zakresie. Wiem również, że jeśli selected
znajduje się wewnątrz innego obiektu i wiążę się z obiektem zewnętrznym, wszystko będzie działać. Ale w tej chwili nie jestem zainteresowany tymi rozwiązaniami.
Zamiast tego mam następujące pytania:
- Jak zapobiec
ng-repeat
tworzeniu zakresu, który prototypowo dziedziczy po zakresie nadrzędnym, i zamiast tego używać zakresu izolowanego mojej dyrektywy? - Dlaczego poziom priorytetu
2000
w mojej dyrektywie nie działa? - Czy korzystając z Batarangu można dowiedzieć się, jaki typ lunety jest używany?
scope: true
dla twojej dyrektywy. Zobacz także (jeśli jeszcze tego nie zrobiłeś) stackoverflow.com/questions/14914213/ ... Również fakt, że dyrektywa będzie używana w wielu miejscach, nie oznacza, że powinniśmy automatycznie używać zakresu izolowanego.ng-repeat
. Myślę, że warto mieć możliwość mieszania samodzielnych dyrektyw zng-repeat
.ng-repeat
nie powinna mieć zakresu.ng-repeat
posiadanie lunety ma sens w typowym przypadku użycia, więc nie sugeruję, aby go zmieniać. Zamiast tego, jak skomentowałem w odpowiedzi Alexa Osborna, myślę, że utworzę dyrektywę powtarzania opartą nang-repeat
tym, że nie stworzy własnego zakresu. Może to być następnie użyte do powtarzania dyrektyw, które mają własne izolowane zakresy.ng-repeat
czy niestandardowej dyrektywy powtarzania bez zakresu. Myślę, że „dzwoniący” powinien wiedzieć o tym, ale nie jest w porządku, aby „wywołujący” (powtarzanie dyrektywy) wiedział, czy jest to powtarzane, czy nie.Odpowiedzi:
OK, dzięki wielu powyższym komentarzom odkryłem zamieszanie. Najpierw kilka punktów do wyjaśnienia:
Oto przykład tego samego kodu, ale z usuniętą dyrektywą:
Oto JSFiddle demonstrujący, że to nie zadziała. Otrzymasz dokładnie takie same wyniki, jak w swojej dyrektywie.
Dlaczego to nie działa? Ponieważ zakresy w AngularJS używają dziedziczenia prototypowego. Wartość
selected
zakresu nadrzędnego jest prymitywna . W JavaScript oznacza to, że zostanie nadpisany, gdy dziecko ustawi tę samą wartość. W zakresach AngularJS obowiązuje złota zasada: wartości modeli powinny zawsze mieć w sobie znak.
. Oznacza to, że nigdy nie powinni być prymitywni. Zobacz tę odpowiedź SO, aby uzyskać więcej informacji.Oto obraz tego, jak początkowo wyglądały lunety.
Po kliknięciu pierwszego elementu zakresy wyglądają teraz następująco:
Zwróć uwagę, że w
selected
zakresie ngRepeat została utworzona nowa właściwość. Zakres sterownika 003 nie został zmieniony.Prawdopodobnie zgadniesz, co się stanie, gdy klikniemy na drugą pozycję:
Więc twój problem w rzeczywistości nie jest spowodowany przez ngRepeat - jest spowodowany złamaniem złotej zasady w AngularJS. Aby to naprawić, wystarczy użyć właściwości obiektu:
Oto drugi JSFiddle pokazujący, że to również działa.
Oto jak początkowo wyglądają lunety:
Po kliknięciu pierwszej pozycji:
W tym przypadku, zgodnie z życzeniem, wpływa to na zakres sterownika.
Ponadto, aby udowodnić, że będzie to nadal działać z twoją dyrektywą z zakresem izolowanym (ponieważ, znowu, nie ma to nic wspólnego z twoim problemem), tutaj jest JSFiddle również do tego, widok musi odzwierciedlać obiekt. Zauważysz, że jedyną konieczną zmianą było użycie obiektu zamiast prymitywu .
Zakresy początkowo:
Zakresy po kliknięciu pierwszej pozycji:
Podsumowując: po raz kolejny problem nie dotyczy zakresu izolowanego ani sposobu działania ngRepeat. Twoim problemem jest to, że łamiesz zasadę, o której wiadomo, że prowadzi do tego właśnie problemu. Modele w AngularJS powinny zawsze mieć rozszerzenie
.
.źródło
.
złota reguła jest wymagana tylko dla zakresów, które mają dziedziczenie prototypowe. W przypadku izolowanych zakresów zmienne, które Cię interesują, są zdefiniowane wscope: {}
definicji zawartej w dyrektywie, a zatem od początku te zmienne będą istniały w izolowanym zakresie. Ponadto nie maskują zmiennych nadrzędnych, ponieważ zakres izolowany nie dziedziczy prototypowo z zakresu nadrzędnego. tj. nie ma zasięgu „rodzica” do zamaskowania..
.Nie próbując bezpośrednio unikać odpowiedzi na pytania, zamiast tego spójrz na następujące skrzypce:
http://jsfiddle.net/dVPLM/
Kluczową kwestią jest to, że zamiast próbować walczyć i zmieniać konwencjonalne zachowanie Angulara, możesz zaprojektować swoją dyrektywę tak, aby działała, zamiast próbować
ng-repeat
ją zastąpić.W Twoim szablonie:
W twojej dyrektywie:
W odpowiedzi na Twoje pytania:
ng-repeat
utworzy zakres, naprawdę nie powinieneś próbować tego zmieniać.źródło
ng-repeat
czy nie. Może kiedy jest napisany po raz pierwszy, nigdy nie jest używany zng-repeat
. I kiedyś w przyszłości może się z nim przyzwyczaićng-repeat
iw tym momencie powinien po prostu działać bez przepisywania. Miejmy nadzieję, że przyszłe wydanie AngularJS to umożliwi.ng-repeat
czy nie. Wygląda jednak na to, że musiałbym przekazać funkcję do dyrektywy, aby mogła modyfikować zmienne w zakresie nadrzędnym, zamiast móc mutować dwukierunkowe wiązanie w zakresie samej dyrektywy. Dyrektywy wiążące dwukierunkowe i dyrektywy wielokrotnego użytku to moje dwie ulubione rzeczy w AngularJS ing-repeat
okazuje się być muchą w maści. Może mógłbym napisaćng-repeat
odpowiednik, który nie tworzy własnego zakresu.