pasar 2 valores de índice $ dentro de ng-repeat anidado


322

Entonces tengo un ng-repeat anidado dentro de otro ng-repeat para construir un menú de navegación. En cada uno <li>del bucle interno ng-repeat, configuro un ng-click que llama al controlador correspondiente para ese elemento del menú pasando el $ index para que la aplicación sepa cuál necesitamos. Sin embargo, también necesito pasar el $ index desde el ng-repeat externo para que la aplicación sepa en qué sección estamos y en qué 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>

aquí hay un Plunker http://plnkr.co/edit/bJUhI9oGEQIql9tahIJN?p=preview


¿Por qué quieres pasar $ index? simplemente pase la referencia del objeto de esta manera ng-click="loadFromMenu(section)". Pasar $ index significa que harás un ciclo para encontrar el objeto que no es necesario.
Moshii

Respuestas:


468

Cada ng-repeat crea un ámbito secundario con los datos pasados, y también agrega una $indexvariable adicional en ese ámbito.

Entonces, lo que debe hacer es llegar al alcance principal y utilizarlo $index.

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

impresionante, así que así es como accedo al $ index externo, pero necesitaba pasar AMBOS valores del índice $. Traté de ponerlos en una matriz y funcionó :)
Tules

16
No tiene que usar una matriz: ng-click="loadFromMenu($parent.$index, $index)"
Mark Rajcok

3
ni siquiera tiene que pasar los índices: en loadFromMenu, debe tener acceso a este objeto, que le dará acceso a: this. $ index y this. $ parent. $ index
Oddman

3
@Oddman, aunque esto es posible, no creo que sea una buena idea, ya que luego conecta su loadFromMenu para que se ejecute en el contexto de un objeto que tiene un alcance con un índice $ y un alcance primario con un índice $. supongamos que, por ejemplo, crea grupos dentro del menú que generan otro ámbito entre los dos importantes: tendrá que cambiar loadFromMenu en lugar de cambiar la llamada a él. Y si en algunos menús necesita llamar loadFromMenu($parent.$parent.$index,$index)y en algunos necesita justo loadFromMenu($parent.$index,$index)entonces, usar this....simplemente no funcionaría.
Epeleg

77
No debe usar $ parent. $ Index ya que no es realmente seguro. Si agrega un ng-if dentro del ciclo, obtiene el $ index desordenado, verifique: plnkr.co/52oIhLfeXXI9ZAynTuAJ
gonzalon

201

Solución mucho más elegante que $parent.$indexestá 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
Este es el método recomendado para lograr este efecto. De hecho, el equipo angular ha expresado varias veces que este es uno de los pocos usos recomendados de la directiva ng-init (ver: enlace ). A menudo encuentro que el uso de $ parent (según la respuesta actualmente aceptada) es un poco un olor a código, ya que generalmente hay una mejor manera de lograr la comunicación $ alcance a $ alcance (Servicios o Eventos de difusión / emisión) y asignándola a un variable nombrada se vuelve más claro lo que representa el valor.
David Beech

2
En mi opinión, esta respuesta es mucho mejor que la aceptada. El uso de $ parent es realmente desaconsejado.
olivarra1

43
Esto deja de funcionar cuando elimina elementos de la lista porque el valor ng-init no se reinicia. Solo es útil si no tiene la intención de eliminar elementos de la lista.
Jesse Greathouse

66
Parece que la sintaxis angular evolucionó. stackoverflow.com/a/31477492/2516560 ahora puede usar "ng-repeat = (clave, valor) en los datos"
Okazari

2
En los días que escribí esta respuesta, esta era la forma de hacerlo para Angular 1.X. Este uso de ng-initse demostró en ng-initdocumentos sin una sola mención en ng-repeatdocumentos, así que escribí aquí + modifiqué los documentos en Github. La ng-repeatsintaxis actual tiene una mejor manera de lograr esto, lo cual es demostrado por @Okazari. Está libre de algunas imperfecciones mencionadas por usted en los comentarios.
vucalur

115

¿Qué pasa con el uso de esta sintaxis (eche un vistazo en este plunker ). Acabo de descubrir esto y es bastante impresionante.

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

Ejemplo:

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

Con esta sintaxis puede dar su propio nombre $indexy diferenciar los dos índices.


8
Creo que esto es mucho más limpio que usar parent cuando tienes múltiples bucles anidados
Yasitha Waduge

En realidad, esto me causó algunos problemas reales al usar el árbol angular-ui para arrastrar / soltar nodos. El índice no parece restablecerse y, como resultado, suceden cosas extrañas.
Mike Taverne

@ MikeTaverne ¿Podrías intentar reproducir en un plunker? Me encantaría ver el comportamiento.
Okazari

44
Esta es la forma correcta de lograr esto y evitar posibles problemas. ng-init funciona para el renderizado inicial, pero si el objeto se actualiza en la página, se rompe.
Eric Martin

¡bueno! pero por favor arregle con agregar "rastrear por" como el ejemplo de plunker.
Danilo

32

Solo para ayudar a alguien que llegue aquí ... No debes usar $ parent. $ Index ya que no es realmente seguro. Si agrega un ng-if dentro del bucle, ¡obtendrá el $ index desordenado!

Manera correcta

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

Verifique: plnkr.co/52oIhLfeXXI9ZAynTuAJ


Tenga en cuenta que el "seguimiento por" no es necesario aquí; eso es algo diferente que se usa para ng-repeat para comprender elementos únicos y observar los cambios en la colección (consulte la sección "Seguimiento y duplicados" de los documentos: docs.angularjs.org / api / ng / directive / ngRepeat ). El punto importante aquí es el "ng-init", esa es la forma correcta con la que los documentos angulares están de acuerdo.
Rebecca

@gonzalon Cómo pasar estos índices como parámetro en ng click
Nagaraj S

Estoy haciendo removeList ($ index) o removeList (rowIndex) No está registrando el índice correctamente en la función Recibo el valor del índice como indefinido. Estoy usando angular 1.5.6
user269867

Esta es la forma correcta, nunca debes acceder a $ parent
Jesú Castillo

3

Cuando se trata de objetos, desea ignorar las identificaciones simples tanto como sea conveniente.

Si cambia la línea de clic a esto, creo que estará bien encaminado:

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

Además, creo que es posible que deba cambiar

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

a algo como

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

Consulte http://docs.angularjs.org/misc/faq y busque ng-class.


1

Solo usa ng-repeat="(sectionIndex, section) in sections"

y eso será utilizable en el siguiente nivel 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>
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.