A abordagem mais confiável e tecnicamente correta é transformar os dados no controlador. Aqui está uma função e uso simples de um pedaço.
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);
Então, sua visão seria assim:
<div class="row" ng-repeat="rows in chunkedData">
<div class="span4" ng-repeat="item in rows">{{item}}</div>
</div>
Se você tiver alguma entrada dentro do ng-repeat
, provavelmente desejará desmarcar / juntar as matrizes à medida que os dados são modificados ou enviados. Veja como isso ficaria em um $watch
, para que os dados estejam sempre disponíveis no formato mesclado original:
$scope.$watch('chunkedData', function(val) {
$scope.data = [].concat.apply([], val);
}, true); // deep watch
Muitas pessoas preferem fazer isso na visualização com um filtro. Isso é possível, mas só deve ser usado para fins de exibição! Se você adicionar entradas nessa exibição filtrada, isso causará problemas que podem ser resolvidos, mas não são bonitos ou confiáveis .
O problema com esse filtro é que ele retorna novas matrizes aninhadas a cada vez. Angular está observando o valor de retorno do filtro. Na primeira vez em que o filtro é executado, o Angular conhece o valor e o executa novamente para garantir a alteração. Se os dois valores forem iguais, o ciclo será encerrado. Caso contrário, o filtro será acionado repetidamente até que sejam iguais, ou o Angular perceberá que um loop de digestão infinito está ocorrendo e será desligado. Como novas matrizes / objetos aninhados não foram rastreados anteriormente pelo Angular, ele sempre vê o valor de retorno diferente do anterior. Para corrigir esses filtros "instáveis", você deve agrupar o filtro em uma memoize
função. lodash
tem uma memoize
função e a versão mais recente do lodash também inclui uma chunk
função, para que possamos criar esse filtro de maneira muito simples usandonpm
módulos e compilando o script com browserify
ou webpack
.
Lembre-se: somente exibição! Filtre no controlador se você estiver usando entradas!
Instale o lodash:
npm install lodash-node
Crie o 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);
});
E aqui está uma amostra com 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>
Encomende itens verticalmente
1 4
2 5
3 6
Em relação às colunas verticais (listar de cima para baixo) em vez de horizontais (da esquerda para a direita), a implementação exata depende da semântica desejada. Listas que se dividem desigualmente podem ser distribuídas de maneiras diferentes. Aqui está uma maneira:
<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;
}
No entanto, a maneira mais direta e simples de obter colunas é usar colunas CSS :
.columns {
columns: 3;
}
<div class="columns">
<div ng-repeat="item in ['a','b','c','d','e','f','g']">
{{item}}
</div>
</div>