passage de valeurs d'index de 2 $ dans ng-repeat imbriqué

322

J'ai donc un ng-repeat imbriqué dans un autre ng-repeat afin de construire un menu nav. Sur chacun <li>de la boucle interne ng-repeat, j'ai défini un ng-click qui appelle le contrôleur approprié pour cet élément de menu en passant l'index $ pour faire savoir à l'application dont nous avons besoin. Cependant, je dois également passer l'index $ à partir de la répétition externe ng afin que l'application sache dans quelle section nous nous trouvons ainsi que quel tutoriel.

<ul ng-repeat="section in sections">
    <li  class="section_title {{section.active}}" >
        {{section.name}}
    </li>
    <ul>
        <li class="tutorial_title {{tutorial.active}}" ng-click="loadFromMenu($index)" ng-repeat="tutorial in section.tutorials">
            {{tutorial.name}}
        </li>
    </ul>
</ul>

voici un Plunker http://plnkr.co/edit/bJUhI9oGEQIql9tahIJN?p=preview

Tules
la source
Pourquoi voulez-vous passer $ index? passez simplement la référence d'objet comme ceci ng-click="loadFromMenu(section)". Passer $ index signifie que vous ferez une boucle pour trouver l'objet qui n'est pas nécessaire.
Moshii

Réponses:

468

Chaque ng-repeat crée une portée enfant avec les données transmises et ajoute également une $indexvariable supplémentaire dans cette portée.

Donc, ce que vous devez faire, c'est atteindre la portée parent et l'utiliser $index.

Voir http://plnkr.co/edit/FvVhirpoOF8TYnIVygE6?p=preview

<li class="tutorial_title {{tutorial.active}}" ng-click="loadFromMenu($parent.$index)" ng-repeat="tutorial in section.tutorials">
    {{tutorial.name}}
</li>
Alex Osborn
la source
génial, c'est ainsi que j'accède à l'index externe $, mais je devais passer les deux valeurs d'index $. J'ai essayé de les mettre dans un tableau et cela a fonctionné :)
Tules
16
Vous n'avez pas besoin d'utiliser un tableau: ng-click="loadFromMenu($parent.$index, $index)"
Mark Rajcok
3
vous n'avez même pas besoin de passer les index - dans le loadFromMenu, il devrait avoir accès à un objet this, qui vous donnera accès à: this. $ index et this. $ parent. $ index
Oddman
3
@Oddman même si cela est possible, je ne pense pas que ce soit une bonne idée, car vous câblez ensuite durement votre loadFromMenu pour qu'il s'exécute dans le contexte d'un objet qui a une étendue avec un index $ et une étendue parent avec un index $. Supposons que vous créiez par exemple des groupes dans le menu qui génèrent une autre étendue entre les deux significatifs - vous devrez changer loadFromMenu au lieu de changer l'appel. Et si, dans certains menus, vous devez appeler loadFromMenu($parent.$parent.$index,$index)et dans certains dont vous avez besoin, l' loadFromMenu($parent.$index,$index)utilisation this....ne fonctionnera tout simplement pas.
epeleg
7
Vous ne devez pas utiliser $ parent. $ Index car ce n'est pas vraiment sûr. Si vous ajoutez un ng-if à l'intérieur de la boucle, vous obtenez l'index $ foiré, vérifiez: plnkr.co/52oIhLfeXXI9ZAynTuAJ
gonzalon
201

Solution beaucoup plus élégante que celle $parent.$indexutilisée ng-init:

<ul ng-repeat="section in sections" ng-init="sectionIndex = $index">
    <li  class="section_title {{section.active}}" >
        {{section.name}}
    </li>
    <ul>
        <li class="tutorial_title {{tutorial.active}}" ng-click="loadFromMenu(sectionIndex)" ng-repeat="tutorial in section.tutorials">
            {{tutorial.name}}
        </li>
    </ul>
</ul>

Plunker: http://plnkr.co/edit/knwGEnOsAWLhLieKVItS?p=info

vucalur
la source
2
Il s'agit de la méthode recommandée pour obtenir cet effet. En fait, l'équipe angulaire a exprimé à quelques reprises que c'est l'une des rares utilisations recommandées de la directive ng-init (voir: lien ). Je trouve souvent que l'utilisation de $ parent (selon la réponse actuellement acceptée) est un peu une odeur de code car il y a généralement un meilleur moyen de réaliser une communication $ scope to $ scope (Services ou Broadcast / Emit Events) et en l'attribuant à un variable nommée, il devient plus clair ce que la valeur représente.
David Beech
2
OMI, cette réponse est bien meilleure que celle acceptée. L'utilisation de $ parent est vraiment déconseillée.
olivarra1
43
Cela cesse de fonctionner lorsque vous supprimez des éléments de la liste car la valeur ng-init ne se réinitialise pas. Il n'est utile que si vous n'avez pas l'intention de supprimer des éléments de la liste.
Jesse Greathouse
6
On dirait que la syntaxe angulaire a évolué. stackoverflow.com/a/31477492/2516560, vous pouvez désormais utiliser "ng-repeat = (clé, valeur) dans les données"
Okazari
2
À l'époque, j'ai écrit cette réponse, c'était la façon de le faire pour Angular 1.X. Cette utilisation de a ng-initété démontrée dans les ng-initdocuments sans aucune mention dans les ng-repeatdocuments, j'ai donc écrit ici + modifié les documents sur Github. La ng-repeatsyntaxe actuelle a un meilleur moyen d'y parvenir, ce qui est démontré par @Okazari. Il est exempt de quelques imperfections que vous avez mentionnées dans les commentaires.
vucalur
115

Qu'en est-il de l'utilisation de cette syntaxe (jetez un oeil dans ce plunker ). Je viens de découvrir cela et c'est assez génial.

ng-repeat="(key,value) in data"

Exemple:

<div ng-repeat="(indexX,object) in data">
    <div ng-repeat="(indexY,value) in object">
       {{indexX}} - {{indexY}} - {{value}}
    </div>
</div>

Avec cette syntaxe, vous pouvez donner votre propre nom $indexet différencier les deux index.

Okazari
la source
8
Je pense que c'est beaucoup plus propre que d'utiliser parent lorsque vous avez plusieurs boucles imbriquées
Yasitha Waduge
En fait, cela m'a causé de réels problèmes lors de l'utilisation de l'arborescence angulaire pour faire glisser / déposer des nœuds. L'index ne semble pas être réinitialisé et des choses étranges se produisent en conséquence.
Mike Taverne
@MikeTaverne Pourriez-vous essayer de reproduire dans un plongeur? J'adorerais voir le comportement.
Okazari
4
C'est la bonne façon d'accomplir cela et d'éviter tout problème potentiel. ng-init fonctionne pour le rendu initial, mais si l'objet est mis à jour sur la page, il se casse.
Eric Martin
bien! mais veuillez corriger en ajoutant "track by" comme l'exemple de plunker.
Danilo
32

Juste pour aider quelqu'un qui arrive ici ... Vous ne devriez pas utiliser $ parent. $ Index car ce n'est pas vraiment sûr. Si vous ajoutez un ng-if à l'intérieur de la boucle, vous obtenez le $ index foiré!

La bonne façon

  <table>
    <tr ng-repeat="row in rows track by $index" ng-init="rowIndex = $index">
        <td ng-repeat="column in columns track by $index" ng-init="columnIndex = $index">

          <b ng-if="rowIndex == columnIndex">[{{rowIndex}} - {{columnIndex}}]</b>
          <small ng-if="rowIndex != columnIndex">[{{rowIndex}} - {{columnIndex}}]</small>

        </td>
    </tr>
  </table>

Vérifier: plnkr.co/52oIhLfeXXI9ZAynTuAJ

gonzalon
la source
Notez que le "suivi par" n'est pas nécessaire ici - c'est une chose distincte utilisée pour ng-repeat pour comprendre les éléments uniques et surveiller les changements dans la collection (voir la section "Suivi et doublons" de la documentation: docs.angularjs.org / api / ng / directive / ngRepeat ). Le point important ici est le "ng-init" - c'est la manière correcte avec laquelle les docs angulaires sont d'accord.
Rebecca
@gonzalon Comment passer ces index en tant que paramètre en un clic
Nagaraj S
Je fais removeList ($ index) ou removeList (rowIndex) Il n'enregistre pas correctement l'index dans la fonction Je reçois une valeur d'index non définie. J'utilise angulaire 1.5.6
user269867
C'est la bonne façon, vous ne devriez jamais accéder à $ parent
Jesú Castillo
3

Lorsque vous traitez avec des objets, vous voulez ignorer les identifiants simples autant que possible.

Si vous changez la ligne de clic en ceci, je pense que vous serez sur la bonne voie:

<li class="tutorial_title {{tutorial.active}}" ng-click="loadFromMenu(tutorial)" ng-repeat="tutorial in section.tutorials">

De plus, je pense que vous devrez peut-être changer

class="tutorial_title {{tutorial.active}}"

à quelque chose comme

ng-class="tutorial_title {{tutorial.active}}"

Voir http://docs.angularjs.org/misc/faq et recherchez ng-class.

kwerle
la source
1

Utilisez simplement ng-repeat="(sectionIndex, section) in sections"

et cela sera utilisable au niveau suivant ng-repeat down.

<ul ng-repeat="(sectionIndex, section) in sections">
    <li  class="section_title {{section.active}}" >
        {{section.name}}
    </li>
    <ul>
        <li ng-repeat="tutorial in section.tutorials">
            {{tutorial.name}}, Your section index is {{sectionIndex}}
        </li>
    </ul>
</ul>
RobKohr
la source