passando 2 $ valori indice all'interno di ng-repeat nidificato


322

Quindi ho un ng-repeat nidificato all'interno di un altro ng-repeat per creare un menu di navigazione. Su ognuno <li>del ciclo interno di ng-repeat ho impostato un ng-click che chiama il controller pertinente per quella voce di menu passando l'indice $ per far sapere all'app che ci serve. Tuttavia, devo anche passare l'indice $ dall'esterno ng-repeat in modo che l'app sappia in quale sezione ci troviamo e in quale tutorial.

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

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


Perché vuoi passare $ index? basta passare il riferimento all'oggetto in questo modo ng-click="loadFromMenu(section)". Passare $ index significa che farai un ciclo per trovare l'oggetto che non è necessario.
Moshii,

Risposte:


468

Ogni ng-repeat crea un ambito figlio con i dati passati e aggiunge anche una $indexvariabile aggiuntiva in quell'ambito.

Quindi quello che devi fare è raggiungere l'ambito genitore e usarlo $index.

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

fantastico, quindi è così che accedo all'indice $ esterno, ma dovevo passare ENTRAMBI i valori dell'indice. Ho provato a metterli in un array e ha funzionato :)
Tules

16
Non è necessario utilizzare un array: ng-click="loadFromMenu($parent.$index, $index)"
Mark Rajcok

3
non devi nemmeno passare gli indici in - in loadFromMenu, dovrebbe avere accesso a questo oggetto, che ti darà accesso a: questo. $ index e questo. $ parent. $ index
Oddman

3
@Oddman, anche se questo è possibile, non credo sia una buona idea, dato che esegui il cablaggio di loadFromMenu per l'esecuzione in un contesto di un oggetto che ha un ambito con un indice $ e un ambito padre con un $ indice. supponiamo che, ad esempio, crei gruppi nel menu che generino un altro ambito tra i due significativi: dovrai cambiare loadFromMenu invece di cambiare la chiamata ad esso. E se in alcuni menu devi chiamare loadFromMenu($parent.$parent.$index,$index)e in alcuni devi semplicemente loadFromMenu($parent.$index,$index)usare this....non funzionerebbe.
Epeleg,

7
Non dovresti usare $ parent. $ Index in quanto non è veramente sicuro. Se aggiungi un ng-if all'interno del loop, ottieni l'indice $ incasinato, controlla: plnkr.co/52oIhLfeXXI9ZAynTuAJ
gonzalon

201

Soluzione molto più elegante di quella che $parent.$indexsta usando 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


2
Questo è il metodo raccomandato per ottenere questo effetto. In effetti il ​​team angolare ha espresso alcune volte che questo è uno dei pochi usi raccomandati della direttiva ng-init (vedi: link ). Trovo spesso l'uso di $ parent (secondo la risposta attualmente accettata) è un po 'un odore di codice in quanto di solito c'è un modo migliore per raggiungere $ scope alla comunicazione $ scope (Servizi o Broadcast / Emit Events) e assegnandolo a un variabile denominata diventa più chiaro ciò che rappresenta il valore.
David Beech,

2
IMO questa risposta è decisamente migliore di quella accettata. L'uso di $ parent è davvero sconsigliato.
olivarra1,

43
Questo smette di funzionare quando si rimuovono elementi dall'elenco perché il valore ng-init non si reinizializza. È utile solo se non intendi rimuovere elementi dall'elenco.
Jesse Greathouse,

6
Sembra che la sintassi angolare si sia evoluta. stackoverflow.com/a/31477492/2516560 ora puoi usare "ng-repeat = (chiave, valore) nei dati"
Okazari,

2
Ai tempi in cui ho scritto questa risposta, questo era il modo di farlo per Angular 1.X. Questo uso di è ng-initstato dimostrato nei ng-initdocumenti senza alcuna menzione nei ng-repeatdocumenti, quindi ho scritto qui + modificato i documenti su Github. La ng-repeatsintassi attuale ha un modo migliore per raggiungere questo obiettivo, come dimostrato da @Okazari. È privo di alcune imperfezioni da te menzionate nei commenti.
Vucalur,

115

Che ne dici di usare questa sintassi (dai un'occhiata a questo plunker ). L'ho appena scoperto ed è davvero fantastico.

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

Esempio:

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

Con questa sintassi è possibile assegnare il proprio nome $indexe differenziare i due indici.


8
Penso che sia molto più pulito dell'uso dei genitori quando hai più cicli nidificati
Yasitha Waduge,

In realtà questo mi ha causato alcuni problemi reali quando ho usato l'albero angolare per trascinare / rilasciare i nodi. L'indice non sembra ripristinarsi e di conseguenza accadono cose strane.
Mike Taverne, l'

@MikeTaverne Potresti provare a riprodurre in un plunker? Mi piacerebbe vedere il comportamento.
Okazari,

4
Questo è il modo corretto per raggiungere questo obiettivo ed evitare eventuali problemi. ng-init funziona per il rendering iniziale, ma se l'oggetto viene aggiornato sulla pagina, si rompe.
Eric Martin,

bene! ma correggi con l'aggiunta di "track by" come nell'esempio del plunker.
Danilo,

32

Solo per aiutare qualcuno che arriva qui ... Non dovresti usare $ parent. $ Index in quanto non è davvero sicuro. Se aggiungi un ng-if all'interno del ciclo, ottieni l'indice $ incasinato!

Giusta direzione

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

Controllare: plnkr.co/52oIhLfeXXI9ZAynTuAJ


Nota che qui non è necessario "tracciare per": è una cosa separata usata per ng-repeat per comprendere elementi unici e guardare le modifiche nella raccolta (vedi la sezione "Tracciamento e duplicati" dei documenti: docs.angularjs.org / api / ng / direttiva / ngRepeat ). Il punto importante qui è "ng-init" - questo è il modo corretto con cui i documenti angolari concordano.
Rebecca,

@gonzalon Come passare questi indici come parametro in ng click
Nagaraj S

Sto facendo removeList ($ index) o removeList (rowIndex) Non registra correttamente l'indice nella funzione Ricevo il valore dell'indice come non definito. Sto usando l'angolare 1.5.6
user269867

Questo è il modo giusto, non dovresti mai accedere a $ parent
Jesú Castillo il

3

Quando hai a che fare con oggetti, vuoi ignorare gli ID semplici tanto comodi.

Se cambi la linea di clic in questo, penso che sarai sulla buona strada:

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

Inoltre, penso che potresti dover cambiare

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

a qualcosa del genere

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

Vedi http://docs.angularjs.org/misc/faq e cerca ng-class.


1

Basta usare ng-repeat="(sectionIndex, section) in sections"

e che sarà utilizzabile al livello successivo 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>
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.