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.

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.


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.


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>

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))">

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.


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.