El enfoque más confiable y técnicamente correcto es transformar los datos en el controlador. Aquí hay una función y uso simple de fragmentos.
function chunk(arr, size) {
var newArr = [];
for (var i=0; i<arr.length; i+=size) {
newArr.push(arr.slice(i, i+size));
}
return newArr;
}
$scope.chunkedData = chunk(myData, 3);
Entonces su vista se vería así:
<div class="row" ng-repeat="rows in chunkedData">
<div class="span4" ng-repeat="item in rows">{{item}}</div>
</div>
Si tiene alguna entrada dentro de ng-repeat
, probablemente querrá desunir / volver a unir las matrices a medida que los datos se modifiquen o se envíen. Así es como se vería en un $watch
, para que los datos siempre estén disponibles en el formato original y combinado:
$scope.$watch('chunkedData', function(val) {
$scope.data = [].concat.apply([], val);
}, true); // deep watch
Muchas personas prefieren lograr esto en la vista con un filtro. ¡Esto es posible, pero solo debe usarse con fines de visualización! Si agrega entradas dentro de esta vista filtrada, causará problemas que pueden resolverse, pero que no son bonitos ni confiables .
El problema con este filtro es que devuelve nuevas matrices anidadas cada vez. Angular está mirando el valor de retorno del filtro. La primera vez que se ejecuta el filtro, Angular conoce el valor, luego lo ejecuta nuevamente para asegurarse de que haya terminado de cambiar. Si ambos valores son iguales, el ciclo finaliza. De lo contrario, el filtro se disparará una y otra vez hasta que sean iguales o Angular se dé cuenta de que se está produciendo un bucle de resumen infinito y se apagará. Debido a que Angular no rastreó previamente nuevas matrices / objetos anidados, siempre ve el valor de retorno como diferente al anterior. Para corregir estos filtros "inestables", debe ajustar el filtro en una memoize
función. lodash
tiene una memoize
función y la última versión de lodash también incluye una chunk
función, por lo que podemos crear este filtro simplemente usandonpm
módulos y compilando el script con browserify
o webpack
.
Recuerde: ¡solo visualización! ¡Filtra en el controlador si estás usando entradas!
Instalar lodash:
npm install lodash-node
Crea el filtro:
var chunk = require('lodash-node/modern/array/chunk');
var memoize = require('lodash-node/modern/function/memoize');
angular.module('myModule', [])
.filter('chunk', function() {
return memoize(chunk);
});
Y aquí hay una muestra con este filtro:
<div ng-repeat="row in ['a','b','c','d','e','f'] | chunk:3">
<div class="column" ng-repeat="item in row">
{{($parent.$index*row.length)+$index+1}}. {{item}}
</div>
</div>
Ordenar artículos verticalmente
1 4
2 5
3 6
En cuanto a las columnas verticales (lista de arriba a abajo) en lugar de horizontales (de izquierda a derecha), la implementación exacta depende de la semántica deseada. Las listas que se dividen de manera desigual se pueden distribuir de diferentes maneras. Aquí hay una manera:
<div ng-repeat="row in columns">
<div class="column" ng-repeat="item in row">
{{item}}
</div>
</div>
var data = ['a','b','c','d','e','f','g'];
$scope.columns = columnize(data, 3);
function columnize(input, cols) {
var arr = [];
for(i = 0; i < input.length; i++) {
var colIdx = i % cols;
arr[colIdx] = arr[colIdx] || [];
arr[colIdx].push(input[i]);
}
return arr;
}
Sin embargo, la forma más directa y sencilla de obtener columnas es usar columnas CSS :
.columns {
columns: 3;
}
<div class="columns">
<div ng-repeat="item in ['a','b','c','d','e','f','g']">
{{item}}
</div>
</div>