L'approccio più affidabile e tecnicamente corretto è trasformare i dati nel controller. Ecco una semplice funzione e utilizzo di blocchi.
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);
Quindi la tua vista sarebbe simile a questa:
<div class="row" ng-repeat="rows in chunkedData">
<div class="span4" ng-repeat="item in rows">{{item}}</div>
</div>
Se hai degli input all'interno di ng-repeat
, probabilmente vorrai sbloccare / ricongiungere gli array man mano che i dati vengono modificati o al momento dell'invio. Ecco come apparirebbe in a $watch
, in modo che i dati siano sempre disponibili nel formato originale e unito:
$scope.$watch('chunkedData', function(val) {
$scope.data = [].concat.apply([], val);
}, true); // deep watch
Molte persone preferiscono eseguire questa operazione nella vista con un filtro. Questo è possibile, ma dovrebbe essere utilizzato solo per scopi di visualizzazione! Se aggiungi input all'interno di questa visualizzazione filtrata, causerà problemi che possono essere risolti, ma non sono belli o affidabili .
Il problema con questo filtro è che restituisce ogni volta nuovi array nidificati. Angular sta guardando il valore di ritorno dal filtro. La prima volta che il filtro viene eseguito, Angular conosce il valore, quindi lo esegue di nuovo per assicurarsi che sia stato modificato. Se entrambi i valori sono uguali, il ciclo è terminato. In caso contrario, il filtro si attiverà ancora e ancora fino a quando non sono uguali, oppure Angular si rende conto che si sta verificando un ciclo digest infinito e si spegne. Poiché i nuovi array / oggetti annidati non erano stati precedentemente tracciati da Angular, vede sempre il valore restituito come diverso dal precedente. Per correggere questi filtri "instabili", è necessario racchiudere il filtro in una memoize
funzione. lodash
ha una memoize
funzione e l'ultima versione di lodash include anche una chunk
funzione, quindi possiamo creare questo filtro molto semplicemente usandonpm
moduli e compilando lo script con browserify
o webpack
.
Ricorda: solo display! Filtra nel controller se stai usando gli input!
Installa lodash:
npm install lodash-node
Crea il 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);
});
Ed ecco un esempio con questo 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>
Ordina gli articoli verticalmente
1 4
2 5
3 6
Per quanto riguarda le colonne verticali (elenco dall'alto in basso) piuttosto che orizzontali (da sinistra a destra), l'implementazione esatta dipende dalla semantica desiderata. Gli elenchi che si dividono in modo non uniforme possono essere distribuiti in modi diversi. Ecco un modo:
<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;
}
Tuttavia, il modo più diretto e semplicemente semplice per ottenere colonne è utilizzare le colonne CSS :
.columns {
columns: 3;
}
<div class="columns">
<div ng-repeat="item in ['a','b','c','d','e','f','g']">
{{item}}
</div>
</div>