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.