javascript - una - ng repeat start angularjs
angular.js ng-repeat para crear una grilla (10)
Intento crear una grilla usando bootstrap 3 y angularjs.
La cuadrícula que intento crear es esta, repetida usando ng-repeat.
<div class="row">
<div class="col-md-4">item</div>
<div class="col-md-4">item</div>
<div class="col-md-4">item</div>
</div>
He intentado usar ng-if
con ($index % 3 == 0)
para agregar las filas, pero parece que esto no funciona bien. ¡Cualquier sugerencia seria genial!
¡Gracias!
EDITAR: Aquí está el código con el que terminé trabajando:
<div ng-repeat="item in items">
<div ng-class="row|($index % 3 == 0)">
<ng-include class="col-sm-4" src="''views/items/item''"></ng-include>
</div>
</div>
Esto debería funcionar
<div ng-repeat="item in items">
<div ng-class="{row : ($index % 3 == 0)}">
...
</div>
</div>
La respuesta aceptada es la solución obvia; sin embargo, la lógica de presentación debe permanecer a la vista y no en los controladores o modelos. Además, no pude hacer funcionar la solución del OP.
Aquí hay dos maneras de crear un sistema de cuadrícula cuando tiene una lista plana (conjunto) de elementos. Diga que nuestra lista de elementos es un alfabeto:
$scope.alphabet = [''A'', ''B'', ''C'', ''D'', ''E'', ''F'', ''G'', ''H'', ''I'', ''J'', ''K'', ''L'', ''M'',
''N'', ''O'', ''P'', ''Q'', ''R'', ''S'', ''T'', ''U'', ''V'', ''W'', ''X'', ''Y'', ''Z''];
Método 1:
Esta es una solución angular pura.
<div class="row" ng-repeat="letter in alphabet track by $index" ng-if="$index % 4 == 0">
<div class="col-xs-3 letter-box"
ng-repeat="i in [$index, $index + 1, $index + 2, $index + 3]"
ng-if="alphabet[i] != null">
<div>Letter {{i + 1}} is: <b> {{alphabet[i]}}</b></div>
</div>
</div>
El bucle externo se ejecuta después de cada 4 iteraciones y crea una fila. Para cada ejecución del bucle externo, el bucle interno itera 4 veces y crea columnas. Como el bucle interno se ejecuta 4 veces independientemente de si tenemos elementos en la matriz o no, el ng-if
asegura que no se creen cols externos si la matriz finaliza antes de que el bucle interno se complete.
Método 2:
Esta es una solución mucho más simple pero requiere angular-filter biblioteca de angular-filter .
<div class="row" ng-repeat="letters in alphabet | chunkBy:4">
<div class="col-xs-3 letter-box" ng-repeat="letter in letters" >
<div>Letter {{$index + 1}} is: <b> {{letter}}</b></div>
</div>
</div>
El bucle externo crea grupos de 4 letras, correspondientes a nuestra ''fila''
[[''A'', ''B'', ''C'', ''D''], [''E'', ''F'', ''G'', ''H''], ... ]
El ciclo interno itera sobre el grupo y crea columnas.
Nota: El método 2 podría requerir la evaluación del filtro para cada iteración del bucle externo, por lo tanto, el método 2 puede no escalarse muy bien para grandes conjuntos de datos.
Mi solución es muy similar a @CodeExpress one. Hice un filtro por batch
que agrupa los elementos de una matriz (el nombre se tomó prestado del filtro homólogo de Twig ). No manejo arreglos asociativos por simplicidad.
angular.module(''myapp.filters'', [])
.filter(''batch'', function() {
var cacheInputs = [];
var cacheResults = [];
return function(input, size) {
var index = cacheInputs.indexOf(input);
if (index !== -1) {
return cacheResults[index];
}
var result = [];
for (i = 0; i < input.length; i += size) {
result.push(input.slice(i, i + size));
}
cacheInputs.push(input);
cacheResults.push(result);
return result;
}
})
;
Se puede usar de esta manera:
<div ng-repeat="itemsRow in items|batch:3">
<div class="row">
<div ng-repeat="item in itemsRow">
<div class="col-md-4">
...
</div>
</div>
</div>
</div>
Los resultados del filtro se almacenan en caché para evitar las 10 $digest() iterations reached. Aborting!
10 $digest() iterations reached. Aborting!
error.
Se podría decir que la solución siguiente no sigue las reglas de cuadrícula de tener divisiones de row
, pero otra solución sería abandonar la clase de row
(o usarla fuera de la ng-repeat
) y usar la clase de clearfix
lugar:
<div class="col-md-12">
<div ng-repeat="item in items">
<div ng-class="{''clearfix'': $index%3 === 0}"></div>
<div class="col-md-4">{{item}}</div>
</div>
</div>
Por lo que puedo ver, esto se ve casi igual que con la clase de row
, pero por favor comente sobre los posibles defectos (excepto el que mencioné anteriormente).
Simplemente puede dividir su matriz en submapas de N dentro de su controlador. Código de muestra:
var array = [''A'',''B'',''C'',''D'',''E'',''F'',''G'',''H''];
var chunk = function(arr, size) {
var newArr = [];
for (var i=0; i<arr.length; i+=size) {
newArr.push(arr.slice(i, i+size));
}
return newArr;
};
$scope.array = chunk(array);
Ahora en el archivo * .html Simplemente ng-repeat
través de la array
<div class="row" ng-repeat="chunk in array">
<div class="column" ng-repeat="item in chunk">
{{item}}
</div>
</div>
Ese entrenamiento para mí :) ¡Buena suerte!
Tomé un método ligeramente diferente usando ngInit . No estoy seguro de si esta es la solución adecuada ya que la documentación de ngInit establece
El único uso apropiado de ngInit es para asociar propiedades especiales de ngRepeat, como se ve en la demostración a continuación. Además de este caso, debe usar controladores en lugar de ngInit para inicializar valores en un ámbito.
No estoy seguro de si esto se debe a ese caso, pero quería alejar esta funcionalidad del controlador para que el diseñador de la plantilla tenga más libertad para agrupar por filas con bootstrap. Todavía no he probado esto para el enlace, pero dado que estoy siguiendo el índice de $ no creo que deba ser un problema.
Me encantaría escuchar comentarios.
Creé un filtro llamado "splitrow" que toma un argumento (el recuento de cuántos elementos en cada fila)
.filter(''splitrow'', function(){
return function (input, count){
var out = [];
if(typeof input === "object"){
for (var i=0, j=input.length; i < j; i+=count) {
out.push(input.slice(i, i+count));
}
}
return out;
}
});
Dentro de la plantilla de vista, organicé las filas de arranque de la siguiente manera:
<div ng-init="rows = (items|splitrow:3)">
<div ng-repeat=''row in rows'' class="row">
<div ng-repeat="item in row track by $index" class="col-md-4">
{{item.property}}
</div>
</div>
</div>
Edité @ Shivam''s Plunker para usar este método. No requiere bibliotecas externas.
Una respuesta tardía, pero utilicé esto y creo que es mejor para algunos casos. Puede utilizar el paquete de angular-filter y su filtro ChunkBy para esto. Aunque este paquete sería un trabajo pesado para esta única tarea, existen otros filtros útiles para diferentes tareas. El código que utilicé es así:
<div class="row mar-t2" ng-repeat="items in posts | chunkBy:3">
<div class="col-md-4" ng-repeat="post in items">
<img ng-src="{{post.featured_url}}" class="img-responsive" />
<a ng-click="modalPop(post.id)"><h1 class="s04-bas2">{{post.title.rendered}}</h1></a>
<div class="s04-spotbox2" ng-bind-html="post.excerpt.rendered"></div>
</div>
</div>
Una versión Angular2 de la solución angular pura de @ CodeExpress.
alphabet: string[] = [''A'', ''B'', ''C'', ''D'', ''E'', ''F'', ''G'', ''H'', ''I'', ''J'', ''K'', ''L'', ''M'',
''N'', ''O'', ''P'', ''Q'', ''R'', ''S'', ''T'', ''U'', ''V'', ''W'', ''X'', ''Y'', ''Z''];
<div *ngIf=''alphabet && alphabet.length''>
<div *ngFor=''#letter of alphabet; #i = index'' >
<div class="row" *ngIf=''i % 4 == 0''>
<div class="col-md-3" *ngFor=''#n of [i,i+1,i+2,i+3]''>
{{alphabet[n]}}
</div>
</div>
</div>
</div>
Usando ng-repeat-start y ng-repeat-end
<div class="row">
<div ng-repeat-start="item in items track by $index" class="col-sm-4">
{{item}}
</div>
<div ng-repeat-end ng-if="($index+1) % 3 == 0" class="clearfix"></div>
</div>
Fácil de adaptar para diferentes consultas de medios usando clases .visible- *
<div class="row">
<div ng-repeat-start="item in items track by $index" class="col-lg-2 col-md-4 col-sm-6">
{{item}}
</div>
<div ng-repeat-end>
<div class="clearfix visible-lg-block" ng-if="($index+1) % 6 == 0"></div>
<div class="clearfix visible-md-block" ng-if="($index+1) % 3 == 0"></div>
<div class="clearfix visible-sm-block" ng-if="($index+1) % 2 == 0"></div>
</div>
</div>
Encuentro claro y conciso tener lógica de gestión de filas fuera del bloque de repetición principal. Separación de intereses :-)
Esta es una vieja respuesta!
Todavía era un poco nuevo en Angular cuando escribí esto. Hay una respuesta mucho mejor debajo de Shivam que sugiero que uses en su lugar. Mantiene la lógica de presentación fuera de su controlador, lo cual es algo muy bueno.
Respuesta original
Siempre puede dividir la lista sobre la que está repitiendo en una lista de listas (con tres elementos cada una) en su controlador. Entonces tu lista es:
$scope.split_items = [[''item1'', ''item2'', ''item3''], [''item4'', ''item5'', ''item6'']];
Y luego repítelo como:
<div ng-repeat="items in split_items" class="row">
<div ng-repeat="item in items" class="col-md-4">
item
</div>
</div>
No estoy seguro si hay una mejor manera. También intenté jugar con ng-if y ng-switch, pero nunca pude hacer que funcionara.