L'approche la plus fiable et la plus techniquement correcte consiste à transformer les données dans le contrôleur. Voici une simple fonction et utilisation de bloc.
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);
Ensuite, votre vue ressemblerait à ceci:
<div class="row" ng-repeat="rows in chunkedData">
<div class="span4" ng-repeat="item in rows">{{item}}</div>
</div>
Si vous avez des entrées dans le ng-repeat
, vous voudrez probablement décoller / rejoindre les tableaux lorsque les données sont modifiées ou lors de la soumission. Voici à quoi cela ressemblerait dans un $watch
, de sorte que les données soient toujours disponibles dans le format d'origine fusionné:
$scope.$watch('chunkedData', function(val) {
$scope.data = [].concat.apply([], val);
}, true); // deep watch
Beaucoup de gens préfèrent accomplir cela dans la vue avec un filtre. Ceci est possible, mais ne doit être utilisé qu'à des fins d'affichage! Si vous ajoutez des entrées dans cette vue filtrée, cela causera des problèmes qui peuvent être résolus, mais qui ne sont ni jolis ni fiables .
Le problème avec ce filtre est qu'il renvoie à chaque fois de nouveaux tableaux imbriqués. Angular surveille la valeur de retour du filtre. La première fois que le filtre s'exécute, Angular connaît la valeur, puis l'exécute à nouveau pour s'assurer qu'elle a bien été modifiée. Si les deux valeurs sont identiques, le cycle est terminé. Sinon, le filtre se déclenchera encore et encore jusqu'à ce qu'ils soient identiques, ou Angular se rend compte qu'une boucle de digestion infinie se produit et s'arrête. Étant donné que les nouveaux tableaux / objets imbriqués n'étaient pas précédemment suivis par Angular, il voit toujours la valeur de retour comme différente de la précédente. Pour corriger ces filtres "instables", vous devez envelopper le filtre dans une memoize
fonction. lodash
a une memoize
fonction et la dernière version de lodash comprend également une chunk
fonction, nous pouvons donc créer ce filtre très simplement en utilisantnpm
modules et compiler le script avec browserify
ou webpack
.
N'oubliez pas: affichage uniquement! Filtrez dans le contrôleur si vous utilisez des entrées!
Installez lodash:
npm install lodash-node
Créez le filtre:
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);
});
Et voici un exemple avec ce filtre:
<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>
Commander les articles verticalement
1 4
2 5
3 6
Concernant les colonnes verticales (liste de haut en bas) plutôt qu'horizontales (de gauche à droite), l'implémentation exacte dépend de la sémantique souhaitée. Les listes qui se divisent de manière inégale peuvent être distribuées de différentes manières. Voici une façon:
<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;
}
Cependant, le moyen le plus direct et le plus simple d'obtenir des colonnes est d'utiliser des colonnes CSS :
.columns {
columns: 3;
}
<div class="columns">
<div ng-repeat="item in ['a','b','c','d','e','f','g']">
{{item}}
</div>
</div>