Angular.js ng-repeat для создания сетки
Я пытаюсь создать сетку, используя bootstrap 3 и angularjs.
Сетка, которую я пытаюсь создать, повторяется с помощью ng-repeat.
<div class="row">
<div class="col-md-4">item</div>
<div class="col-md-4">item</div>
<div class="col-md-4">item</div>
</div>
Я попытался использовать ng-if
с ($index % 3 == 0)
, чтобы добавить строки, но это, похоже, не работает правильно. Любые предложения были бы замечательными!
Спасибо!
EDIT: Здесь код, который я закончил, сработал:
<div ng-repeat="item in items">
<div ng-class="row|($index % 3 == 0)">
<ng-include class="col-sm-4" src="'views/items/item'"></ng-include>
</div>
</div>
Ответы
Ответ 1
Это старый ответ!
Я все еще был немного новым в Angular, когда писал это. Из Shivam есть намного лучший ответ, который я предлагаю вам использовать вместо этого. Он выводит логику презентации из вашего контроллера, что очень хорошо.
Оригинальный ответ
Вы всегда можете разбить список, который вы повторяете, в список списков (по три элемента каждый) в вашем контроллере. Таким образом, вы указываете следующее:
$scope.split_items = [['item1', 'item2', 'item3'], ['item4', 'item5', 'item6']];
И затем повторите его как:
<div ng-repeat="items in split_items" class="row">
<div ng-repeat="item in items" class="col-md-4">
item
</div>
</div>
Не уверен, есть ли лучший способ. Я также пытался играть с ng-if и ng-switch, но я никогда не смог заставить его работать.
Ответ 2
Принятый ответ - очевидное решение, однако логика представления должна оставаться в поле зрения, а не в контроллерах или моделях. Также я не смог заставить OP-решение работать.
Вот два способа создания сетки, когда у вас есть плоский список (массив) элементов.
Скажем, наш список предметов - это алфавит:
Plunker здесь
$scope.alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
Способ 1:
Это чистое решение angular.
<div class="row" ng-repeat="letter in alphabet track by $index" ng-if="$index % 4 == 0">
<div class="col-xs-3 letter-box"
ng-repeat="i in [$index, $index + 1, $index + 2, $index + 3]"
ng-if="alphabet[i] != null">
<div>Letter {{i + 1}} is: <b> {{alphabet[i]}}</b></div>
</div>
</div>
Внешний цикл выполняется после каждых 4 итераций и создает строку. Для каждого запуска внешнего цикла внутренний цикл повторяется 4 раза и создает столбцы. Поскольку внутренний цикл работает 4 раза независимо от того, есть ли у нас элементы в массиве или нет, ng-if
гарантирует, что никакие посторонние столбцы не создаются, если массив заканчивается до завершения внутреннего цикла.
Способ 2:
Это гораздо более простое решение, но требует angular-filter.
<div class="row" ng-repeat="letters in alphabet | chunkBy:4">
<div class="col-xs-3 letter-box" ng-repeat="letter in letters" >
<div>Letter {{$index + 1}} is: <b> {{letter}}</b></div>
</div>
</div>
Внешний цикл создает группы из 4 букв, соответствующие нашей строке
[['A', 'B', 'C', 'D'], ['E', 'F', 'G', 'H'], ... ]
Внутренний цикл выполняет итерацию по группе и создает столбцы.
Примечание. Метод 2 может потребовать оценки фильтра для каждой итерации внешнего цикла, поэтому метод 2 может не очень хорошо масштабироваться для огромных наборов данных.
Ответ 3
Вы можете просто вырезать массив в подмассивах N внутри вашего контроллера. Образец кода:
var array = ['A','B','C','D','E','F','G','H'];
var chunk = function(arr, size) {
var newArr = [];
for (var i=0; i<arr.length; i+=size) {
newArr.push(arr.slice(i, i+size));
}
return newArr;
};
$scope.array = chunk(array, 2);
Теперь в *.html файле. Вы просто ng-repeat
через array
<div class="row" ng-repeat="chunk in array">
<div class="col-md-6" ng-repeat="item in chunk">
{{item}}
</div>
</div>
Эта тренировка для меня :) Удачи!
Ответ 4
Можно сказать, что нижеприведенное решение не соответствует правилам сетки с row
divs, но другим решением было бы отказаться от класса row
(или использовать его вне ng-repeat
) и использовать clearfix
вместо:
<div class="col-md-12">
<div ng-repeat="item in items">
<div ng-class="{'clearfix': $index%3 === 0}"></div>
<div class="col-md-4">{{item}}</div>
</div>
</div>
Насколько я вижу, это выглядит почти так же, как и с классом row
, но прокомментируйте возможные недостатки (кроме тех, которые были упомянуты выше).
Ответ 5
Использование ng-repeat-start и ng-repeat-end
<div class="row">
<div ng-repeat-start="item in items track by $index" class="col-sm-4">
{{item}}
</div>
<div ng-repeat-end ng-if="($index+1) % 3 == 0" class="clearfix"></div>
</div>
Легко адаптироваться для разных запросов к мультимедиа, используя классы .visible - *
<div class="row">
<div ng-repeat-start="item in items track by $index" class="col-lg-2 col-md-4 col-sm-6">
{{item}}
</div>
<div ng-repeat-end>
<div class="clearfix visible-lg-block" ng-if="($index+1) % 6 == 0"></div>
<div class="clearfix visible-md-block" ng-if="($index+1) % 3 == 0"></div>
<div class="clearfix visible-sm-block" ng-if="($index+1) % 2 == 0"></div>
</div>
</div>
Я считаю ясным и кратким, чтобы иметь логику управления строкой вне основного блока повтора. Разделение проблем: -)
Ответ 6
Немного поздно ответ, но я использовал это, и я верю, что это лучше для некоторых случаев. Вы можете использовать Angular Фильтр и его фильтр ChunkBy для этого. Несмотря на то, что этот пакет будет тяжелым, для этой единственной задачи есть другие полезные фильтры для разных задач. Используемый мной код выглядит так:
<div class="row mar-t2" ng-repeat="items in posts | chunkBy:3">
<div class="col-md-4" ng-repeat="post in items">
<img ng-src="{{post.featured_url}}" class="img-responsive" />
<a ng-click="modalPop(post.id)"><h1 class="s04-bas2">{{post.title.rendered}}</h1></a>
<div class="s04-spotbox2" ng-bind-html="post.excerpt.rendered"></div>
</div>
</div>
Ответ 7
Я использовал несколько иной метод, используя ngInit. Я не уверен, что это подходящее решение, так как в документации ngInit указано
Единственное подходящее использование ngInit - это для сглаживания специальных свойств ngRepeat, как показано в демонстрации ниже. Помимо этого случая, вы должны использовать контроллеры вместо ngInit для инициализации значений в области.
Я не уверен, что это подпадает под этот случай, но я хотел переместить эту функциональность в сторону от контроллера, чтобы дать дизайнеру шаблона более легкую группировку по строкам с помощью бутстрапа. Я все еще не тестировал это для привязки, но, видя, что я отслеживаю по индексу $index, я не думаю, что это должно быть проблемой.
Хотелось бы услышать отзывы.
Я создал фильтр под названием "splitrow", который принимает один аргумент (количество элементов в каждой строке)
.filter('splitrow', function(){
return function (input, count){
var out = [];
if(typeof input === "object"){
for (var i=0, j=input.length; i < j; i+=count) {
out.push(input.slice(i, i+count));
}
}
return out;
}
});
Внутри шаблона представления я организовал строки бутстрапа следующим образом:
<div ng-init="rows = (items|splitrow:3)">
<div ng-repeat='row in rows' class="row">
<div ng-repeat="item in row track by $index" class="col-md-4">
{{item.property}}
</div>
</div>
</div>
Я редактировал @Shivam Plunker, чтобы использовать этот метод. Он не требует внешних библиотек.
Plunker
Ответ 8
Мое решение очень похоже на @CodeExpress. Я создал фильтр batch
, который группирует элементы массива (имя заимствовано из Twig counterpart filter).
Я не обрабатываю ассоциативные массивы для простоты.
angular.module('myapp.filters', [])
.filter('batch', function() {
var cacheInputs = [];
var cacheResults = [];
return function(input, size) {
var index = cacheInputs.indexOf(input);
if (index !== -1) {
return cacheResults[index];
}
var result = [];
for (i = 0; i < input.length; i += size) {
result.push(input.slice(i, i + size));
}
cacheInputs.push(input);
cacheResults.push(result);
return result;
}
})
;
Его можно использовать следующим образом:
<div ng-repeat="itemsRow in items|batch:3">
<div class="row">
<div ng-repeat="item in itemsRow">
<div class="col-md-4">
...
</div>
</div>
</div>
</div>
Результаты фильтрации кэшируются, чтобы избежать ошибки 10 $digest() iterations reached. Aborting!
.
Ответ 9
An Angular2 версия решения @CodeExpress pure angular.
alphabet: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
<div *ngIf='alphabet && alphabet.length'>
<div *ngFor='#letter of alphabet; #i = index' >
<div class="row" *ngIf='i % 4 == 0'>
<div class="col-md-3" *ngFor='#n of [i,i+1,i+2,i+3]'>
{{alphabet[n]}}
</div>
</div>
</div>
</div>
Ответ 10
Это должно работать
<div ng-repeat="item in items">
<div ng-class="{row : ($index % 3 == 0)}">
...
</div>
</div>