Najbardziej niezawodnym i technicznie poprawnym podejściem jest transformacja danych w kontrolerze. Oto prosta funkcja i użycie fragmentu.
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);
Wtedy Twój widok wyglądałby tak:
<div class="row" ng-repeat="rows in chunkedData">
<div class="span4" ng-repeat="item in rows">{{item}}</div>
</div>
Jeśli masz jakiekolwiek dane wejściowe w ramach ng-repeat
, prawdopodobnie będziesz chciał odblokować / ponownie dołączyć tablice, gdy dane są modyfikowane lub przesyłane. Oto jak wyglądałoby to w formacie a $watch
, aby dane były zawsze dostępne w oryginalnym, scalonym formacie:
$scope.$watch('chunkedData', function(val) {
$scope.data = [].concat.apply([], val);
}, true); // deep watch
Wiele osób woli to osiągnąć w widoku z filtrem. Jest to możliwe, ale powinno być używane tylko do celów wyświetlania! Jeśli dodasz dane wejściowe w tym przefiltrowanym widoku, spowoduje to problemy, które można rozwiązać, ale nie są ładne ani niezawodne .
Problem z tym filtrem polega na tym, że za każdym razem zwraca nowe zagnieżdżone tablice. Angular obserwuje wartość zwracaną przez filtr. Przy pierwszym uruchomieniu filtru Angular zna wartość, a następnie uruchamia go ponownie, aby upewnić się, że została zmieniona. Jeśli obie wartości są takie same, cykl jest zakończony. Jeśli nie, filtr będzie uruchamiał się raz po raz, aż będą takie same, lub Angular zorientuje się, że występuje nieskończona pętla trawienia i wyłączy się. Ponieważ nowe zagnieżdżone tablice / obiekty nie były wcześniej śledzone przez Angular, zawsze widzi wartość zwracaną jako inną niż poprzednia. Aby naprawić te „niestabilne” filtry, musisz umieścić filtr w memoize
funkcji. lodash
ma memoize
funkcję, a najnowsza wersja lodash zawiera również chunk
funkcję, więc możemy utworzyć ten filtr w bardzo prosty sposób za pomocąnpm
modułów i kompilowanie skryptu za pomocą browserify
lub webpack
.
Pamiętaj: tylko wyświetlaj! Filtruj w kontrolerze, jeśli używasz wejść!
Zainstaluj lodash:
npm install lodash-node
Utwórz filtr:
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);
});
A oto próbka z tym filtrem:
<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>
Zamawiaj pozycje pionowo
1 4
2 5
3 6
Jeśli chodzi o kolumny pionowe (lista od góry do dołu), a nie poziome (od lewej do prawej), dokładna implementacja zależy od pożądanej semantyki. Listy, które dzielą się nierównomiernie, można podzielić na różne sposoby. Oto jeden sposób:
<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;
}
Jednak najbardziej bezpośrednim i po prostu prostym sposobem uzyskania kolumn jest użycie kolumn CSS :
.columns {
columns: 3;
}
<div class="columns">
<div ng-repeat="item in ['a','b','c','d','e','f','g']">
{{item}}
</div>
</div>