przekazanie 2 $ wartości indeksu w zagnieżdżonym powtórzeniu ng


322

Więc mam powtórzenie ng zagnieżdżone w innym powtórzeniu ng, aby zbudować menu nawigacyjne. Na każdym <li>w wewnętrznej pętli powtórzenia ng ustawiam kliknięcie ng, które wywołuje odpowiedni kontroler dla tego elementu menu, przekazując indeks $, aby poinformować aplikację, której potrzebujemy. Jednak muszę również przekazać indeks $ z zewnętrznego ng-repeat, aby aplikacja wiedziała, w której sekcji się znajdujemy, a także w jakim tutorialu.

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

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


Dlaczego chcesz przekazać indeks $? po prostu przekaż odwołanie do obiektu w ten sposób ng-click="loadFromMenu(section)". Przekazanie indeksu $ oznacza, że ​​wykonasz pętlę, aby znaleźć niepotrzebny obiekt.
Moshii,

Odpowiedzi:


468

Każde powtórzenie ng tworzy zakres potomny z przekazanymi danymi, a także dodaje dodatkową $indexzmienną w tym zakresie.

Musisz więc dotrzeć do zakresu nadrzędnego i użyć go $index.

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

niesamowite, więc w ten sposób uzyskuję dostęp do zewnętrznego indeksu $, ale musiałem przekazać OBA wartości indeksu $. Próbowałem umieścić je w tablicy i zadziałało :)
Tules

16
Nie musisz używać tablicy: ng-click="loadFromMenu($parent.$index, $index)"
Mark Rajcok

3
nie musisz nawet przekazywać indeksów - w loadFromMenu powinien on mieć dostęp do tego obiektu, który da ci dostęp do: tego. $ indeksu i tego. $ rodzica. $ indeksu
Oddman

3
@Oddman, nawet jeśli jest to możliwe, nie sądzę, aby to był dobry pomysł, ponieważ wtedy mocno podłączasz loadFromMenu do działania w kontekście obiektu, który ma zakres z indeksem $ i zakres nadrzędny z indeksem $. załóżmy, że na przykład tworzysz w menu grupy, które generują inny zakres pomiędzy dwoma znaczącymi - będziesz musiał zmienić loadFromMenu zamiast zmieniać wywołanie do niego. A jeśli w niektórych menu musisz zadzwonić, loadFromMenu($parent.$parent.$index,$index)aw niektórych potrzebujesz właśnie loadFromMenu($parent.$index,$index)wtedy, użycie this....po prostu nie zadziała.
epeleg

7
Nie powinieneś używać $ parent. $ Index, ponieważ nie jest to tak naprawdę bezpieczne. Jeśli dodasz ng-if wewnątrz pętli, otrzymasz błędny
gonzalon

201

O wiele bardziej eleganckie rozwiązanie niż $parent.$indexużycie 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
Jest to zalecana metoda osiągnięcia tego efektu. W rzeczywistości zespół Angular kilkakrotnie stwierdził, że jest to jedno z niewielu zalecanych zastosowań dyrektywy ng-init (patrz: link ). Często zdarza mi się, że użycie $ parent (zgodnie z obecnie akceptowaną odpowiedzią) jest trochę zapachowym kodem, ponieważ zwykle istnieje lepszy sposób na uzyskanie $ $ do komunikacji $ scope (Usługi lub Wydarzenia Broadcast / Emit) i przypisanie go do nazwana zmienna staje się wyraźniejsze, co reprezentuje wartość.
David Beech

2
IMO ta odpowiedź jest znacznie lepsza niż zaakceptowana. Używanie $ parent jest naprawdę, bardzo odradzane.
olivarra1

43
To przestaje działać, gdy usuwasz elementy z listy, ponieważ wartość ng-init nie inicjuje się ponownie. Jest to przydatne tylko, jeśli nie zamierzasz usuwać elementów z listy.
Jesse Greathouse

6
Wygląda na to, że ewoluowała składnia kątowa. stackoverflow.com/a/31477492/2516560 możesz teraz używać „ng-repeat = (klucz, wartość) w danych”
Okazari

2
W czasach, kiedy pisałem tę odpowiedź, był to sposób na zrobienie tego dla Angulara 1.X. To użycie ng-initzostało zademonstrowane w ng-initdokumentach bez żadnej wzmianki w ng-repeatdokumentach, więc napisałem tutaj + zmieniłem dokumenty w Github. Obecna ng-repeatskładnia ma lepszy sposób na osiągnięcie tego, o czym świadczy @Okazari. Jest wolny od pewnych niedoskonałości wymienionych przez ciebie w komentarzach.
vucalur

115

Co powiesz na użycie tej składni (spójrz na ten fragmentator ). Właśnie to odkryłem i jest to całkiem niesamowite.

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

Przykład:

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

Dzięki tej składni możesz nadać własne imię $indexi rozróżnić dwa indeksy.


8
Myślę, że jest to o wiele czystsze niż używanie rodzica, gdy masz wiele zagnieżdżonych pętli
Yasitha Chinthaka,

W rzeczywistości spowodowało to pewne problemy podczas korzystania z drzewa kątowego do przeciągania / upuszczania węzłów. Wygląda na to, że indeks się nie resetuje, w wyniku czego dzieją się dziwne rzeczy.
Mike Taverne,

@MikeTaverne Czy możesz spróbować odtworzyć w plunkerze? Chciałbym zobaczyć zachowanie.
Okazari,

4
To jest właściwy sposób, aby to osiągnąć i uniknąć potencjalnych problemów. ng-init działa dla początkowego renderowania, ale jeśli obiekt zostanie zaktualizowany na stronie, psuje się.
Eric Martin

dobrze! ale popraw to, dodając „śledź przez”, tak jak w przypadku plunkera.
Danilo

32

Aby pomóc komuś, kto się tu dostanie ... Nie powinieneś używać $ parent. $ Index, ponieważ nie jest to naprawdę bezpieczne. Jeśli dodasz ng-if wewnątrz pętli, dostaniesz błąd indeksu $!

Właściwy sposób

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

Sprawdź: plnkr.co/52oIhLfeXXI9ZAynTuAJ


Zauważ, że „śledzenie według” nie jest tutaj potrzebne - jest to osobna rzecz używana dla ng-repeat, aby zrozumieć unikalne elementy i obserwować zmiany w kolekcji (patrz sekcja „Śledzenie i duplikaty” w dokumentacji: docs.angularjs.org / api / ng / wytyczna / ngRepeat ). Ważnym punktem jest tutaj „ng-init” - jest to właściwy sposób, z którym zgadzają się doktoranci.
Rebecca

@ Gonzalon Jak przekazać te indeksy jako parametr w kliknięciu
Nagaraj S

Wykonuję removeList ($ index) lub removeList (rowIndex) Nie rejestruje poprawnie indeksu w funkcji. Otrzymuję wartość indeksu jako niezdefiniowaną. Używam kątowej 1.5.6
użytkownik269867

To jest właściwy sposób, nigdy nie powinieneś uzyskiwać dostępu do $ rodzic
Jesú Castillo

3

Kiedy masz do czynienia z obiektami, chcesz zignorować proste identyfikatory tak samo, jak wygodne.

Jeśli zmienisz linię kliknięcia na to, myślę, że będziesz na dobrej drodze:

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

Myślę też, że możesz potrzebować zmiany

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

do czegoś takiego

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

Zobacz http://docs.angularjs.org/misc/faq i poszukaj klasy ng.


1

Po prostu użyj ng-repeat="(sectionIndex, section) in sections"

i będzie to możliwe do użycia na następnym poziomie powtórzenia ng w dół.

<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>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.