AngularJS - come ottenere un riferimento al risultato filtrato ngRepeat


129

Sto usando una direttiva ng-repeat con filtro in questo modo:

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

e posso vedere bene i risultati di rendering; ora voglio eseguire un po 'di logica su quel risultato nel mio controller. La domanda è: come posso prendere il riferimento agli elementi del risultato?

Aggiornare:


Solo per chiarire: sto cercando di creare un completamento automatico, ho questo input:

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

e quindi i risultati filtrati:

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

ora voglio navigare nel risultato e selezionare uno degli elementi.

Risposte:


270

AGGIORNAMENTO : ecco un modo più semplice di quello che c'era prima.

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

Quindi $scope.filteredItemsè accessibile.


Grazie per la risposta, consultare il mio aggiornamento. Come lo implementeresti, nota che ottengo l'intero elenco di articoli su init
Shlomi Schwartz,

super cool, grazie per quello. Vorrei che fosse una funzionalità integrata di NG
Shlomi Schwartz il

3
Il problema con questo approccio è che se guardi la proprietà assegnata, finirai per inviare spam $ digest (uno per iterazione) ... Forse c'è un modo per evitarlo?
Juho Vepsäläinen,

1
Se guardo l'oggetto di ricerca e console.log filteredItemsottengo sempre i dati un filtro in seguito. Non è il risultato del filtro appena modificato, ma quello del precedente cambiamento. Qualche idea?
ProblemsOfSumit

4
Qualcuno può spiegarmi, perché funziona? Posso capire che una variabile da $ scope è accessibile nell'ambito di ripetizione (ereditarietà dell'ambito), ma viceversa? Come? Alcuni documenti sono apprezzati. Grazie
dalvarezmartinez1

30

Ecco la versione del filtro della soluzione di Andy Joslin.

Aggiornamento: BREAKING CHANGE. A partire dalla versione 1.3.0-beta.19 ( questo commit ) i filtri non hanno un contesto e thissaranno associati all'ambito globale. Puoi passare il contesto come argomento o utilizzare la nuova sintassi di aliasing in 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);
  };
});

Quindi a tuo avviso

<!-- 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>

Che ti dà accesso a $scope.filteredItems.


Grazie! Potresti spiegare come funziona il codice filtro? Non ho familiarità con $ parse e i documenti angolari non mi hanno aiutato a decodificare come funziona esattamente il tuo filtro.
Magne,

2
@Magne Nessun problema! Per favore, controlla l'aggiornamento, perché potrebbe farti risparmiare un po 'di dolore e sofferenza lungo la strada. Per rispondere alla tua domanda, in breve, $parseè il compilatore di espressioni di Angular . Ad esempio, prenderà la stringa 'some.object.property' e restituirà una funzione che ti consente di impostare o ottenere un valore in detto percorso per un determinato contesto. Lo sto usando per impostare i risultati del filtro sul $ scope qui, in particolare. Spero che questo risponda alla tua domanda.
kevinjamesus86,

23

Prova qualcosa del genere, il problema con ng-repeat è che crea un ambito figlio a causa del quale non puoi accedere

filteritems

dal controller

<li ng-repeat="doc in $parent.filteritems = (docs | filter:searchitems)" ></li>

16

Aggiornare:

Anche dopo la 1.3.0. se vuoi metterlo nell'ambito del controller o del genitore non puoi farlo come sintassi. Ad esempio se ho il seguente codice:

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

quanto sopra non funzionerà. Il modo per aggirarlo è usare $ parent in questo modo:

<li ng-repeat="label in ($parent.labelResults = (labels | filter:query))">

È bene notare che se hai un limite per filtrare su questo. Non si rifletterà in $ parent.labelResults
Zack

Se ottengo console.log labelResultssempre i dati un filtro più tardi. Non è il risultato del filtro appena modificato, ma quello del precedente cambiamento. Non hai avuto questo problema?
Anna,

10

Ho trovato una versione leggermente migliore della soluzione di Andy. Nella sua soluzione ng-repeat posiziona un orologio sull'espressione che contiene il compito. Ogni ciclo digest valuterà quell'espressione e assegnerà il risultato alla variabile scope.

Il problema con questa soluzione è che potresti incorrere in problemi di assegnazione se sei in un ambito figlio. Questo è lo stesso motivo per cui dovresti avere un punto in ng-model .

L'altra cosa che non mi piace di questa soluzione è che nasconde la definizione della matrice filtrata da qualche parte nel markup della vista. Se viene utilizzato in più punti nella vista o nel controller, può creare confusione.

Una soluzione più semplice è semplicemente posizionare un orologio nel controller su una funzione che esegue l'assegnazione:

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

Questa funzione verrà valutata durante ogni ciclo digest, quindi le prestazioni dovrebbero essere comparabili con la soluzione di Andy. Puoi anche aggiungere un numero qualsiasi di incarichi nella funzione per mantenerli tutti in un unico posto anziché sparpagliati nella vista.

Nella vista, dovresti semplicemente utilizzare direttamente l'elenco filtrato:

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

Ecco un violino in cui questo viene mostrato in uno scenario più complicato.


Super pulito e non inquina la struttura, bello!
kuzyn,

questa soluzione è perfetta per me ... stavo usando la ripetizione della raccolta di ionic invece di n ripetizione ... ecco perché la risposta accettata non ha funzionato per me
Lakshay

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.