передача 2 $ значений индекса во вложенном ng-repeat


322

Итак, у меня есть ng-repeat, вложенный в другой ng-repeat, чтобы создать навигационное меню. Для каждого <li>внутреннего цикла ng-repeat я устанавливаю ng-click, который вызывает соответствующий контроллер для этого пункта меню, передавая $ index, чтобы приложение узнало, какой из них нам нужен. Однако мне нужно также передать $ index из внешнего ng-repeat, чтобы приложение знало, в каком разделе мы находимся, а также в каком учебнике.

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

вот плункер http://plnkr.co/edit/bJUhI9oGEQIql9tahIJN?p=preview


Почему вы хотите передать $ index? просто передайте ссылку на объект, как это ng-click="loadFromMenu(section)". Передача $ index означает, что вы выполните цикл, чтобы найти ненужный объект.
Моши

Ответы:


468

Каждый ng-repeat создает дочернюю область с переданными данными, а также добавляет дополнительную $indexпеременную в эту область.

Итак, вам нужно достичь родительской области и использовать ее $index.

См. 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>

классно, вот как я получаю доступ к внешнему индексу $, но мне нужно было передать оба значения индекса $. Я попытался поместить их в массив, и это сработало :)
Tules

16
Вам не нужно использовать массив: ng-click="loadFromMenu($parent.$index, $index)"
Марк Райкок

3
вам даже не нужно передавать индексы - в loadFromMenu он должен иметь доступ к объекту this, который даст вам доступ к: this. $ index и this. $ parent. $ index
Oddman

3
@Oddman, хотя это возможно, я не думаю, что это хорошая идея, так как вы затем жестко подключаете свой loadFromMenu для запуска в контексте объекта, который имеет область видимости с $ index и родительскую область с $ index. Предположим, что вы, например, создаете группы в меню, которые генерируют другую область между двумя значимыми - вам придется изменить loadFromMenu вместо того, чтобы изменять его вызов. И если в некоторых меню вам нужно позвонить, loadFromMenu($parent.$parent.$index,$index)а в некоторых вам просто нужно, loadFromMenu($parent.$index,$index)то использование не this....будет работать.
Epeleg

7
Вы не должны использовать $ parent. $ Index, так как это не совсем безопасно. Если вы добавляете ng-if внутри цикла, вы получаете беспорядочный индекс $, проверьте: plnkr.co/52oIhLfeXXI9ZAynTuAJ
gonzalon

201

Это более элегантное решение, чем $parent.$indexиспользование 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>

Плункер: http://plnkr.co/edit/knwGEnOsAWLhLieKVItS?p=info


2
Это рекомендуемый метод достижения этого эффекта. На самом деле команда разработчиков Angular несколько раз заявляла, что это одно из немногих рекомендуемых применений директивы ng-init (см. Ссылку ). Я часто нахожу использование $ parent (согласно принятому в настоящее время ответу) запахом кода, так как обычно есть лучший способ достижения $ scope to $ scope Communication (Services или Broadcast / Emit Events) и присвоения его именованная переменная становится понятнее, что представляет собой значение.
Дэвид Бич,

2
ИМО этот ответ намного лучше, чем принято. Использование $ parent действительно, действительно не рекомендуется.
olivarra1

43
Это перестает работать, когда вы удаляете элементы из списка, потому что значение ng-init не переинициализируется. Это полезно, только если вы не собираетесь удалять элементы из списка.
Джесси Грейтхаус

6
Похоже, угловой синтаксис развился. stackoverflow.com/a/31477492/2516560 теперь вы можете использовать «ng-repeat = (ключ, значение) в данных»
Okazari

2
В те дни, когда я писал этот ответ, это был способ сделать это для Angular 1.X. Это использование ng-initбыло продемонстрировано в ng-initдокументах без единого упоминания в ng-repeatдокументах, поэтому я написал здесь + исправил документы на Github. Текущий ng-repeatсинтаксис имеет лучший способ добиться этого, что демонстрирует @Okazari. Он свободен от некоторых недостатков, упомянутых вами в комментариях.
Vucalur

115

Как насчет использования этого синтаксиса (взгляните на этот плункер ). Я только что обнаружил это, и это довольно здорово.

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

Пример:

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

С помощью этого синтаксиса вы можете дать собственное имя $indexи дифференцировать два индекса.


8
Я думаю, что это намного чище, чем использование родителя, когда у вас есть несколько вложенных циклов
Yasitha Waduge

На самом деле это вызвало у меня некоторые реальные проблемы при использовании angular-ui-tree для перетаскивания узлов. Кажется, что индекс не сбрасывается, и в результате происходят странные вещи.
Майк Таверн

@MikeTaverne Не могли бы вы попытаться воспроизвести в плункер? Я хотел бы увидеть поведение.
Оказари

4
Это правильный способ сделать это и избежать любых потенциальных проблем. ng-init работает для начального рендера, но если объект обновляется на странице, он ломается.
Эрик Мартин

хорошо! но, пожалуйста, исправьте, добавив "track by", как пример с plunker.
Данило

32

Просто чтобы помочь кому-то, кто попал сюда ... Вы не должны использовать индекс $ parent. $, Поскольку это не совсем безопасно. Если вы добавите ng-if внутри цикла, вы получите беспорядочный индекс $ index!

Правильно

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

Проверить: plnkr.co/52oIhLfeXXI9ZAynTuAJ


Обратите внимание, что здесь «отслеживать по» здесь не нужно - это отдельная вещь, используемая для ng-repeat для понимания уникальных элементов и отслеживания изменений в коллекции (см. Раздел «Отслеживание и дубликаты» документации: docs.angularjs.org / api / ng / directive / ngRepeat ). Важным моментом здесь является «ng-init» - это правильный путь, с которым согласуются угловые документы.
Ребекка

@gonzalon Как передать эти индексы в качестве параметра при щелчке мышью
Nagaraj S

Я делаю removeList ($ index) или removeList (rowIndex). Неправильная запись индекса в функции. Я получаю значение индекса как неопределенное. Я использую угловой 1.5.6
user269867

Это правильный путь, вы никогда не должны обращаться к $ parent
Jesú Castillo

3

Когда вы имеете дело с объектами, вы хотите игнорировать простые идентификаторы настолько, насколько это удобно.

Если вы измените строку клика на это, я думаю, что вы будете хорошо на вашем пути:

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

Кроме того, я думаю, что вам может понадобиться изменить

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

что-то вроде

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

Смотрите http://docs.angularjs.org/misc/faq и ищите ng-класс.


1

Просто использовать ng-repeat="(sectionIndex, section) in sections"

и это будет полезно на следующем уровне 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>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.