I'm trying to create a grid using bootstrap 3 and angularjs.
我正在尝试使用bootstrap 3和angularjs创建一个网格。
The grid I'm trying to create is this, repeated using ng-repeat.
我尝试创建的网格是这个,使用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>
I've tried using ng-if
with ($index % 3 == 0)
to add the rows, but this doesn't seem to be working right. Any suggestions would be great!
我尝试过使用ng-if ($index % 3 == 0)添加行,但这似乎并没有正常工作。任何建议都很好!
Thank you!
谢谢你!
EDIT: Here's the code I ended up going with that worked:
编辑:这是我最后使用的代码:
<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>
10 个解决方案
#1
20
This is an old answer!
这是一个古老的答案!
I was still a bit new on Angular when I wrote this. There is a much better answer below from Shivam that I suggest you use instead. It keeps presentation logic out of your controller, which is a very good thing.
当我写这个的时候,我还是有点新的角度。下面是来自Shivam的一个更好的答案,我建议您使用它。它将表示逻辑从控制器中分离出来,这是一件很好的事情。
Original answer
原来的答案
You can always split the list you are repeating over into a list of lists (with three items each) in your controller. So you list is:
您总是可以将重复的列表分割成一个列表(每个列表包含三个项目)。所以你列表:
$scope.split_items = [['item1', 'item2', 'item3'], ['item4', 'item5', 'item6']];
And then repeat it as:
然后重复如下:
<div ng-repeat="items in split_items" class="row">
<div ng-repeat="item in items" class="col-md-4">
item
</div>
</div>
Not sure if there is a better way. I have also tried playing around with ng-if and ng-switch but I could never get it to work.
不确定是否有更好的方法。我也尝试过使用ng-if和ng-switch,但我无法让它工作。
#2
71
The accepted answer is the obvious solution however presentation logic should remain in view and not in controllers or models. Also I wasn't able to get the OP's solution to work.
公认的答案是显而易见的解决方案,但是表示逻辑应该保留在视图中,而不是在控制器或模型中。我也没能得到OP的解决方案。
Here are two ways to do create grid system when you have a flat list(array) of items. Say our item list is a alphabet:
当你有一个平面的项目列表(数组)时,这里有两种创建网格系统的方法。假设我们的项目列表是一个字母表:
恰好在这里
$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'];
Method 1:
This is a pure angular solution.
这是一个纯角解。
<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>
The outer loop execute after every 4 iterations and creates a row. For each run of the outer loop the inner loop iterates 4 times and creates columns. Since the inner loop runs 4 times regardless of whether we have elements in array or not, the ng-if
makes sure that no extraneous cols are created if the array ends before inner loop completes.
外部循环每4次迭代后执行一次,并创建一个行。对于每次外部循环的运行,内部循环迭代4次并创建列。由于内循环运行4次,而不管数组中是否有元素,因此ng-if确保在内部循环完成之前,如果数组结束,则不会创建任何无关的cols。
Method 2:
This is much simpler solution but requires angular-filter library.
这是一种简单得多的解决方案,但是需要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>
The outer loop creates groups of 4 letters, corresponding to our 'row'
外部循环创建4个字母的组,对应于我们的“row”
[['A', 'B', 'C', 'D'], ['E', 'F', 'G', 'H'], ... ]
The inner loop iterates over the group and creates columns.
内部循环遍历组并创建列。
Note: Method 2 might require evaluation of filter for each iteration of outer loop, hence method 2 may not scale very well for huge data sets.
注意:方法2可能需要对每个外环迭代的过滤器进行评估,因此对于大型数据集,方法2可能不能很好地扩展。
#3
8
You can simply chunk your array into subarrays of N inside of your controller. Sample code:
你可以简单地将数组分割成数组的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);
Now in *.html file You simply ng-repeat
through the array
现在在*。只需通过数组进行ng-repeat即可获得html文件
<div class="row" ng-repeat="chunk in array">
<div class="column" ng-repeat="item in chunk">
{{item}}
</div>
</div>
That workout for me :) Good luck!
我的锻炼:)祝你好运!
#4
3
One might say that the below solution does not follow the grid rules of having row
divs, but another solution would be to drop the row
class ( or use it outside of the ng-repeat
) and use the clearfix
class instead:
有人可能会说,下面的解决方案不遵循具有行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>
As far as I can see, this looks almost the same as with row
class, but please comment on possible flaws (except the one I mentioned above).
在我看来,这与row类几乎是一样的,但是请评论一下可能的缺陷(除了上面提到的那个)。
#5
3
Using ng-repeat-start and ng-repeat-end
使用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>
Easy to adapt for different media query using .visible-* classes
易于适应使用.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>
I find clear and concise to have row management logic outside of the main repeat block. Separation of concerns :-)
我发现在主重复块之外有行管理逻辑是清晰和简洁的。关注点分离:-)
#6
2
A bit late answer but i used this and i belive it is better for some cases. You can use Angular Filter package and its ChunkBy filter for this. Although this package would be a heavy lifting for this single task, there is other useful filters in it for different tasks. The code i used is like this:
回答有点晚,但我用了这个,我相信在某些情况下会更好。你可以用角滤盒和它的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
0
I took a slightly different method using ngInit. I'm not sure if this is the appropriate solution since the ngInit documentation states
我使用ngInit采用了稍微不同的方法。我不确定这是否是合适的解决方案,因为ngInit文档说明了这一点
The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
ngInit的唯一适当用法是对ngRepeat的特殊属性进行混叠,如下面的演示所示。除了这种情况,您应该使用控制器而不是ngInit来初始化作用域上的值。
I'm not really sure if this falls under that case, but I wanted to move this functionality away from the controller to give the template designer easier freedom to group by rows with bootstrap. I still haven't tested this for binding, but seeing as i'm tracking by $index I don't think that should be a problem.
我不太确定这是否属于那种情况,但我想把这个功能从控制器中移开,以便模板设计器更容易地使用引导程序对行进行分组。我还没有对它进行绑定测试,但是由于我使用的是$index,所以我不认为这是一个问题。
Would love to hear feedback.
希望听到反馈。
I created a filter called "splitrow" that takes one argument (the count of how many items in each row)
我创建了一个名为“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;
}
});
Within the view template I organized the bootstrap rows as follows:
在视图模板中,我对引导行进行了如下组织:
<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>
I edited @Shivam's Plunker to use this method. It requires no external libraries.
我编辑了@Shivam的柱塞器来使用这个方法。它不需要外部库。
砰砰作响
#8
0
My solution is very similar to @CodeExpress one. I made a batch
filter that groups items of an array (the name is borrowed it from Twig's counterpart filter). I don't handle associative arrays for simplicity's sake.
我的解决方案非常类似于@CodeExpress one。我做了一个批处理过滤器,将数组的项目分组(名称是从Twig的对应过滤器中借用的)。为了简单起见,我不处理关联数组。
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;
}
})
;
It can be used this way:
可以这样使用:
<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>
The filter results are cached to avoid the 10 $digest() iterations reached. Aborting!
error.
筛选结果被缓存,以避免10 $digest()迭代达到。流产!错误。
#9
0
An Angular2 version of @CodeExpress's pure angular solution.
一个盎格鲁2版本的@CodeExpress的纯角度解。
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
0
This should work
这应该工作
<div ng-repeat="item in items">
<div ng-class="{row : ($index % 3 == 0)}">
...
</div>
</div>
#1
20
This is an old answer!
这是一个古老的答案!
I was still a bit new on Angular when I wrote this. There is a much better answer below from Shivam that I suggest you use instead. It keeps presentation logic out of your controller, which is a very good thing.
当我写这个的时候,我还是有点新的角度。下面是来自Shivam的一个更好的答案,我建议您使用它。它将表示逻辑从控制器中分离出来,这是一件很好的事情。
Original answer
原来的答案
You can always split the list you are repeating over into a list of lists (with three items each) in your controller. So you list is:
您总是可以将重复的列表分割成一个列表(每个列表包含三个项目)。所以你列表:
$scope.split_items = [['item1', 'item2', 'item3'], ['item4', 'item5', 'item6']];
And then repeat it as:
然后重复如下:
<div ng-repeat="items in split_items" class="row">
<div ng-repeat="item in items" class="col-md-4">
item
</div>
</div>
Not sure if there is a better way. I have also tried playing around with ng-if and ng-switch but I could never get it to work.
不确定是否有更好的方法。我也尝试过使用ng-if和ng-switch,但我无法让它工作。
#2
71
The accepted answer is the obvious solution however presentation logic should remain in view and not in controllers or models. Also I wasn't able to get the OP's solution to work.
公认的答案是显而易见的解决方案,但是表示逻辑应该保留在视图中,而不是在控制器或模型中。我也没能得到OP的解决方案。
Here are two ways to do create grid system when you have a flat list(array) of items. Say our item list is a alphabet:
当你有一个平面的项目列表(数组)时,这里有两种创建网格系统的方法。假设我们的项目列表是一个字母表:
恰好在这里
$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'];
Method 1:
This is a pure angular solution.
这是一个纯角解。
<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>
The outer loop execute after every 4 iterations and creates a row. For each run of the outer loop the inner loop iterates 4 times and creates columns. Since the inner loop runs 4 times regardless of whether we have elements in array or not, the ng-if
makes sure that no extraneous cols are created if the array ends before inner loop completes.
外部循环每4次迭代后执行一次,并创建一个行。对于每次外部循环的运行,内部循环迭代4次并创建列。由于内循环运行4次,而不管数组中是否有元素,因此ng-if确保在内部循环完成之前,如果数组结束,则不会创建任何无关的cols。
Method 2:
This is much simpler solution but requires angular-filter library.
这是一种简单得多的解决方案,但是需要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>
The outer loop creates groups of 4 letters, corresponding to our 'row'
外部循环创建4个字母的组,对应于我们的“row”
[['A', 'B', 'C', 'D'], ['E', 'F', 'G', 'H'], ... ]
The inner loop iterates over the group and creates columns.
内部循环遍历组并创建列。
Note: Method 2 might require evaluation of filter for each iteration of outer loop, hence method 2 may not scale very well for huge data sets.
注意:方法2可能需要对每个外环迭代的过滤器进行评估,因此对于大型数据集,方法2可能不能很好地扩展。
#3
8
You can simply chunk your array into subarrays of N inside of your controller. Sample code:
你可以简单地将数组分割成数组的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);
Now in *.html file You simply ng-repeat
through the array
现在在*。只需通过数组进行ng-repeat即可获得html文件
<div class="row" ng-repeat="chunk in array">
<div class="column" ng-repeat="item in chunk">
{{item}}
</div>
</div>
That workout for me :) Good luck!
我的锻炼:)祝你好运!
#4
3
One might say that the below solution does not follow the grid rules of having row
divs, but another solution would be to drop the row
class ( or use it outside of the ng-repeat
) and use the clearfix
class instead:
有人可能会说,下面的解决方案不遵循具有行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>
As far as I can see, this looks almost the same as with row
class, but please comment on possible flaws (except the one I mentioned above).
在我看来,这与row类几乎是一样的,但是请评论一下可能的缺陷(除了上面提到的那个)。
#5
3
Using ng-repeat-start and ng-repeat-end
使用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>
Easy to adapt for different media query using .visible-* classes
易于适应使用.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>
I find clear and concise to have row management logic outside of the main repeat block. Separation of concerns :-)
我发现在主重复块之外有行管理逻辑是清晰和简洁的。关注点分离:-)
#6
2
A bit late answer but i used this and i belive it is better for some cases. You can use Angular Filter package and its ChunkBy filter for this. Although this package would be a heavy lifting for this single task, there is other useful filters in it for different tasks. The code i used is like this:
回答有点晚,但我用了这个,我相信在某些情况下会更好。你可以用角滤盒和它的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
0
I took a slightly different method using ngInit. I'm not sure if this is the appropriate solution since the ngInit documentation states
我使用ngInit采用了稍微不同的方法。我不确定这是否是合适的解决方案,因为ngInit文档说明了这一点
The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
ngInit的唯一适当用法是对ngRepeat的特殊属性进行混叠,如下面的演示所示。除了这种情况,您应该使用控制器而不是ngInit来初始化作用域上的值。
I'm not really sure if this falls under that case, but I wanted to move this functionality away from the controller to give the template designer easier freedom to group by rows with bootstrap. I still haven't tested this for binding, but seeing as i'm tracking by $index I don't think that should be a problem.
我不太确定这是否属于那种情况,但我想把这个功能从控制器中移开,以便模板设计器更容易地使用引导程序对行进行分组。我还没有对它进行绑定测试,但是由于我使用的是$index,所以我不认为这是一个问题。
Would love to hear feedback.
希望听到反馈。
I created a filter called "splitrow" that takes one argument (the count of how many items in each row)
我创建了一个名为“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;
}
});
Within the view template I organized the bootstrap rows as follows:
在视图模板中,我对引导行进行了如下组织:
<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>
I edited @Shivam's Plunker to use this method. It requires no external libraries.
我编辑了@Shivam的柱塞器来使用这个方法。它不需要外部库。
砰砰作响
#8
0
My solution is very similar to @CodeExpress one. I made a batch
filter that groups items of an array (the name is borrowed it from Twig's counterpart filter). I don't handle associative arrays for simplicity's sake.
我的解决方案非常类似于@CodeExpress one。我做了一个批处理过滤器,将数组的项目分组(名称是从Twig的对应过滤器中借用的)。为了简单起见,我不处理关联数组。
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;
}
})
;
It can be used this way:
可以这样使用:
<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>
The filter results are cached to avoid the 10 $digest() iterations reached. Aborting!
error.
筛选结果被缓存,以避免10 $digest()迭代达到。流产!错误。
#9
0
An Angular2 version of @CodeExpress's pure angular solution.
一个盎格鲁2版本的@CodeExpress的纯角度解。
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
0
This should work
这应该工作
<div ng-repeat="item in items">
<div ng-class="{row : ($index % 3 == 0)}">
...
</div>
</div>