AngularJS - Comment obtenir une référence de résultat filtré ngRepeat

129

J'utilise une directive ng-repeat avec un filtre comme ceci:

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

et je peux voir les résultats rendus très bien; maintenant, je veux exécuter une logique sur ce résultat dans mon contrôleur. La question est de savoir comment puis-je récupérer la référence des éléments de résultat?

Mettre à jour:


Juste pour clarifier: j'essaie de créer une saisie semi-automatique, j'ai cette entrée:

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

puis les résultats filtrés:

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

maintenant je veux parcourir le résultat et sélectionner l'un des éléments.

Shlomi Schwartz
la source

Réponses:

271

MISE À JOUR : Voici un moyen plus simple que ce qui existait auparavant.

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

Puis $scope.filteredItemsest accessible.

Andrew Joslin
la source
Merci pour la réponse, veuillez consulter ma mise à jour. Comment implémenteriez-vous cela, notez que j'obtiens la liste complète des éléments sur init
Shlomi Schwartz
super cool, merci pour ça. Je souhaite que ce soit une fonctionnalité intégrée de NG
Shlomi Schwartz
3
Le problème avec cette approche est que si vous regardez la propriété attribuée, vous finirez par spammer $ digests (un par itération) ... Peut-être y a-t-il un moyen d'éviter cela?
Juho Vepsäläinen
1
Si je regarde l'objet de recherche et console.log, j'obtiens filteredItemstoujours les données un filtre plus tard. Ce n'est pas le résultat du filtre qui vient d'être modifié, mais celui du changement précédent. Des idées?
ProblemsOfSumit
4
Quelqu'un peut-il m'expliquer, pourquoi cela fonctionne-t-il? Je peux comprendre qu'une variable de la portée $, est accessible dans la portée de répétition (héritage de la portée), mais l'inverse? Comment? Une certaine documentation est appréciée. Merci
dalvarezmartinez1
30

Voici la version filtrée de la solution d'Andy Joslin.

Mise à jour: BREAKING CHANGE. Depuis la version 1.3.0-beta.19 ( ce commit ), les filtres n'ont pas de contexte et thisseront liés à la portée globale. Vous pouvez soit passer le contexte en tant qu'argument, soit utiliser la nouvelle syntaxe d' alias dans 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);
  };
});

Alors à votre avis

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

Ce qui vous donne accès à $scope.filteredItems.

kevinjamesus86
la source
Merci! Pouvez-vous expliquer comment fonctionne le code de filtre? Je ne suis pas familier avec $ parse, et les documents angulaires ne m'ont pas aidé à décoder le fonctionnement exact de votre filtre.
Magne le
2
@Magne Pas de problème! Veuillez consulter la mise à jour, car elle peut vous éviter des douleurs et des souffrances plus tard. Pour répondre à votre question, en bref, $parseest le compilateur d'expression d'Angular . Par exemple, il prendra la chaîne 'some.object.property' et retournera une fonction qui vous permet de définir ou d'obtenir une valeur sur ledit chemin pour un spécifié le contexte. Je l'utilise pour définir les résultats du filtre sur la portée $ ici, en particulier. J'espère que cela répond à votre question.
kevinjamesus86
23

Essayez quelque chose comme ça, le problème avec le ng-repeat est qu'il crée une portée enfant à cause de cela vous ne pouvez pas accéder

éléments filtrants

du contrôleur

<li ng-repeat="doc in $parent.filteritems = (docs | filter:searchitems)" ></li>
imal hasaranga perera
la source
16

Mettre à jour:

Même après 1.3.0. si vous voulez le mettre sur la portée du contrôleur ou du parent, vous ne pouvez pas le faire avec comme syntaxe. Par exemple si j'ai le code suivant:

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

ce qui précède ne fonctionnera pas . La façon de le contourner consiste à utiliser le $ parent comme suit:

<li ng-repeat="label in ($parent.labelResults = (labels | filter:query))">
Gal Bracha
la source
Il est bon de noter que si vous avez une limite de filtrage à ce sujet. Cela ne sera pas reflété dans le $ parent.labelResults
Zack
Si je console.log labelResultsreçois toujours les données un filtre plus tard. Ce n'est pas le résultat du filtre qui vient d'être modifié, mais celui du changement précédent. N'avez-vous pas eu ce problème?
Anna
10

J'ai proposé une version légèrement meilleure de la solution d'Andy. Dans sa solution ng-repeat place une montre sur l'expression qui contient l'affectation. Chaque boucle de résumé évaluera cette expression et affectera le résultat à la variable de portée.

Le problème avec cette solution est que vous pouvez rencontrer des problèmes d'affectation si vous êtes dans une étendue enfant. C'est la même raison pour laquelle vous devriez avoir un point dans ng-model .

L'autre chose que je n'aime pas dans cette solution est qu'elle enterre la définition du tableau filtré quelque part dans le balisage de la vue. S'il est utilisé à plusieurs endroits de votre vue ou de votre contrôleur, cela peut prêter à confusion.

Une solution plus simple consiste simplement à placer une montre dans votre contrôleur sur une fonction qui effectue l'affectation:

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

Cette fonction sera évaluée au cours de chaque cycle de digest afin que les performances soient comparables à celles de la solution d'Andy. Vous pouvez également ajouter n'importe quel nombre d'affectations dans la fonction pour les garder toutes au même endroit plutôt que dispersées dans la vue.

Dans la vue, vous utiliseriez simplement la liste filtrée directement:

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

Voici un violon où cela est montré dans un scénario plus compliqué.

Dave Johnson
la source
Super propre et ne pollue pas la structure, bien!
kuzyn
cette solution est parfaite pour moi .. j'utilisais la répétition de collection d'ionic au lieu de ng repeat..c'est pourquoi la réponse acceptée n'a pas fonctionné pour moi
Lakshay