AngularJS - jak uzyskać odniesienie do wyniku filtrowanego przez ngRepeat

129

Używam dyrektywy ng-repeat z takim filtrem:

ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4"

i widzę dobrze renderowane wyniki; teraz chcę uruchomić logikę na tym wyniku w moim kontrolerze. Pytanie brzmi, jak mogę pobrać odniesienie do elementów wyników?

Aktualizacja:


Dla wyjaśnienia: próbuję utworzyć autouzupełnianie, mam takie dane wejściowe:

<input id="queryInput" ng-model="query" type="text" size="30" placeholder="Enter query">

a następnie przefiltrowane wyniki:

<ul>
   <li  ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4">{{item.name}}</li>
</ul>

teraz chcę przejść do wyniku i wybrać jedną z pozycji.

Shlomi Schwartz
źródło

Odpowiedzi:

272

UPDATE : Oto prostszy sposób niż to, co było wcześniej.

 <input ng-model="query">
 <div ng-repeat="item in (filteredItems = (items | orderBy:'order_prop' | filter:query | limitTo:4))">
   {{item}}
 </div>

Wtedy $scope.filteredItemsjest dostępny.

Andrew Joslin
źródło
Dzięki za odpowiedź, zobacz moją aktualizację. Jak byś to zaimplementował, zwróć uwagę, że całą listę pozycji dostaję na init
Shlomi Schwartz
super super, dzięki za to. Chciałbym, żeby to była wbudowana funkcja NG
Shlomi Schwartz
3
Problem z tym podejściem polega na tym, że jeśli obserwujesz przypisaną właściwość, skończysz za spamowaniem $ Digests (jeden na iterację) ... Może jest jakiś sposób, aby tego uniknąć?
Juho Vepsäläinen
1
Jeśli oglądam obiekt wyszukiwania i console.log filteredItems, zawsze otrzymuję dane o jeden filtr później. To nie jest wynik zmienionego właśnie filtra, ale ten z poprzedniej zmiany. Jakieś pomysły?
ProblemsOfSumit
4
Czy ktoś może mi wyjaśnić, dlaczego to działa? Rozumiem, że zmienna z zakresu $ jest dostępna w zakresie powtórzeń (dziedziczenie zakresu), ale na odwrót? W jaki sposób? Niektóre dokumenty są mile widziane. Dzięki
dalvarezmartinez1
30

Oto filtracyjna wersja rozwiązania Andy'ego Joslina.

Aktualizacja: REWELACYJNA ZMIANA. Od wersji 1.3.0-beta.19 ( to zatwierdzenie ) filtry nie mają kontekstu i thisbędą powiązane z zakresem globalnym. Możesz przekazać kontekst jako argument lub użyć nowej składni aliasingu w ngRepeat , 1.3.0-beta.17 +.

// pre 1.3.0-beta.19
yourModule.filter("as", function($parse) {
  return function(value, path) {
    return $parse(path).assign(this, value);
  };
});

// 1.3.0-beta.19+
yourModule.filter("as", function($parse) {
  return function(value, context, path) {
    return $parse(path).assign(context, value);
  };
});

Wtedy twoim zdaniem

<!-- pre 1.3.0-beta.19 -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 | as:'filteredItems'">
 {{item}}
</div>

<!-- 1.3.0-beta.19+ -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 | as:this:'filteredItems'">
 {{item}}
</div>

<!-- 1.3.0-beta.17+ ngRepeat aliasing -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 as filteredItems">
 {{item}}
</div>

Co daje ci dostęp do $scope.filteredItems.

kevinjamesus86
źródło
Dzięki! Czy mógłbyś wyjaśnić, jak działa kod filtru? Nie jestem zaznajomiony z $ parse, a dokumentacja kątowa nie pomogła mi zdekodować, jak dokładnie działa twój filtr.
Magne,
2
@Magne Nie ma problemu! Sprawdź jednak aktualizację, ponieważ może to zaoszczędzić trochę bólu i cierpienia w przyszłości. Aby odpowiedzieć na twoje pytanie, w skrócie, $parsejest kompilatorem wyrażeń Angulara. Na przykład, weźmie ciąg „some.object.property” i zwróci funkcję, która pozwala ustawić lub pobrać wartość na wspomnianej ścieżce dla określonej kontekst. Używam go konkretnie do ustawienia wyników filtru w zakresie $ scope. Mam nadzieję, że to odpowiada na twoje pytanie.
kevinjamesus86
24

Spróbuj czegoś takiego, problem z powtórzeniem ng polega na tym, że tworzy zakres potomny, ponieważ nie możesz uzyskać dostępu

filteritems

ze sterownika

<li ng-repeat="doc in $parent.filteritems = (docs | filter:searchitems)" ></li>
imal hasaranga perera
źródło
16

Aktualizacja:

Nawet po 1.3.0. jeśli chcesz umieścić go na zakres kontrolera lub rodzica nie można tego zrobić z jak składni. Na przykład, jeśli mam następujący kod:

<div>{{labelResults}}</div>
<li ng-repeat="label in (labels | filter:query | as labelResults)">
</div>

powyższe nie zadziała. Aby to obejść, użyj elementu $ parent w następujący sposób:

<li ng-repeat="label in ($parent.labelResults = (labels | filter:query))">
Gal Bracha
źródło
Warto zauważyć, że jeśli masz ograniczenie do filtrowania tego. Nie zostanie to odzwierciedlone w $ parent.labelResults
Zack
Jeśli console.log labelResultszawsze otrzymuję dane o jeden filtr później. To nie jest wynik zmienionego właśnie filtra, ale ten z poprzedniej zmiany. Nie miałeś tego problemu?
Anna
10

Wymyśliłem nieco lepszą wersję rozwiązania Andy'ego. W swoim rozwiązaniu ng-repeat zwraca uwagę na wyrażenie zawierające przypisanie. Każda pętla podsumowania oceni to wyrażenie i przypisze wynik do zmiennej zakresu.

Problem z tym rozwiązaniem polega na tym, że możesz napotkać problemy z przypisaniem, jeśli jesteś w zakresie podrzędnym. To jest ten sam powód, dla którego powinieneś mieć kropkę w modelu ng .

Inną rzeczą, której nie lubię w tym rozwiązaniu, jest to, że zakopuje definicję przefiltrowanej tablicy gdzieś w znaczniku widoku. Jeśli jest używany w wielu miejscach w widoku lub kontrolerze, może być mylący.

Prostszym rozwiązaniem jest po prostu umieszczenie zegarka w kontrolerze na funkcji, która dokonuje przypisania:

$scope.$watch(function () {
    $scope.filteredItems = $scope.$eval("items | orderBy:'order_prop' | filter:query | limitTo:4");
});

Ta funkcja będzie oceniana podczas każdego cyklu trawienia, więc wydajność powinna być porównywalna z rozwiązaniem Andy'ego. Możesz również dodać dowolną liczbę przypisań w funkcji, aby zachować je wszystkie w jednym miejscu, a nie rozproszone w widoku.

W widoku wystarczy bezpośrednio użyć przefiltrowanej listy:

<ul>
    <li  ng-repeat="item in filteredItems">{{item.name}}</li>
</ul>

Oto skrzypce, na których pokazano to w bardziej skomplikowanym scenariuszu.

Dave Johnson
źródło
Super czysty i nie zanieczyszcza struktury, fajnie!
kuzyn
to rozwiązanie jest dla mnie idealne .. używałem kolekcji ionic powtórz zamiast ng powtórz ... dlatego zaakceptowana odpowiedź nie zadziałała dla mnie
Lakshay