Krótka odpowiedź : czy naprawdę potrzebujesz takiej funkcji, czy możesz skorzystać z właściwości? http://jsfiddle.net/awnqm/1/
Długa odpowiedź
Dla uproszczenia opiszę tylko Twój przypadek - ngRepeat dla tablicy obiektów. Pominę też kilka szczegółów.
AngularJS używa brudnego sprawdzania do wykrywania zmian. Po uruchomieniu aplikacja działa $digest
dla $rootScope
. $digest
wykona przemierzanie najpierw w głąb hierarchii zakresu . Wszystkie lunety mają listę zegarków. Każdy zegarek ma ostatnią wartość (początkowo initWatchVal
). Dla każdego zakresu dla wszystkich zegarków $digest
uruchamia go, pobiera bieżącą wartość ( watch.get(scope)
) i porównuje ją z watch.last
. Jeśli bieżąca wartość nie jest równa watch.last
(zawsze przy pierwszym porównaniu) $digest
ustawia się dirty
na true
. Gdy wszystkie zakresy są przetwarzane, jeśli dirty == true
$digest
rozpoczyna się kolejne przejście w głąb $rootScope
. $digest
kończy się, gdy dirty == false lub liczba przejść == 10. W tym drugim przypadku błąd „Osiągnięto 10 $ Digest () iteracji”. będą rejestrowane.
Teraz o ngRepeat
. Dla każdego watch.get
wywołania przechowuje obiekty z kolekcji (zwracając wartość getEntities
) z dodatkowymi informacjami w pamięci podręcznej ( HashQueueMap
wg hashKey
). Dla każdego watch.get
wywołania ngRepeat
próbuje pobrać obiekt hashKey
z pamięci podręcznej. Jeśli nie istnieje w pamięci podręcznej, ngRepeat
przechowuje ją w pamięci podręcznej, tworzy nowy zakres, umieszcza na nim obiekt, tworzy element DOM itp .
Teraz o hashKey
. Zwykle hashKey
jest to unikalny numer generowany przez nextUid()
. Ale może to być funkcja . hashKey
jest przechowywany w obiekcie po wygenerowaniu do wykorzystania w przyszłości.
Dlaczego twój przykład generuje błąd : funkcja getEntities()
zawsze zwraca tablicę z nowym obiektem. Ten obiekt nie ma hashKey
i nie istnieje w ngRepeat
pamięci podręcznej. Tak więc ngRepeat
na każdym watch.get
generuje nowy zakres z nowym zegarkiem dla {{entity.id}}
. Ten zegarek na początku watch.get
ma watch.last == initWatchVal
. A więc watch.get() != watch.last
. Tak $digest
zaczyna się nowy trawers. ngRepeat
Tworzy więc nowy zakres z nowym zegarkiem. Więc ... po 10 trawersach pojawia się błąd.
Jak możesz to naprawić
- Nie twórz nowych obiektów przy każdym
getEntities()
połączeniu.
- Jeśli potrzebujesz stworzyć nowe obiekty, możesz dodać
hashKey
do nich metodę. Przykłady można znaleźć w tym temacie .
Mam nadzieję, że ludzie, którzy znają wnętrze AngularJS, poprawią mnie, jeśli się w czymś pomylę.
Do not create new objects on every getEntities() call.
można to naprawić dość łatwo w ten sposób:<div ng-repeat="entity in entities = (entities || getEntities())">
getEntities()
zawsze zwraca tę samą tablicę, jeśli tablica kiedykolwiek się zmieni, nie dostaniesz jej wng-repeat
Zainicjuj tablicę poza powtórzeniem
źródło
getEntities()
zwraca coś innego w cyklu życia programu. Załóżmy na przykład, żegetEntities()
wyzwala to plik$http.get
. Kiedy get w końcu się rozwiąże (wykonałeś połączenie AJAX),entities
zostanie już zainicjowany.The only appropriate use of ngInit is for aliasing special properties of ngRepeat. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
Zostało to zgłoszone tutaj i otrzymało tę odpowiedź:
Możesz zobaczyć, że to zachowanie zniknie, jeśli przeniesiesz tablicę poza kontroler główny:
ponieważ teraz zwraca za każdym razem ten sam obiekt. Może być konieczne ponowne zaprojektowanie modelu, aby użyć właściwości w zakresie zamiast funkcji:
źródło
Na podstawie komentarza @przno
Przy okazji, drugie rozwiązanie @Artem Andreev sugeruje, że nie działa w Angular 1.1.4 i nowszych, natomiast pierwsze nie rozwiązuje problemu. Na razie obawiam się, że jest to mniej ostre rozwiązanie bez wad funkcjonalności
źródło
Item.id
jest tym, co powinno b. Dzięki