如何使用bootstrap将ng-repeat数据分成三列

我正在使用ng-repeat与我的代码,我有'n'的数字基于ng重复的文本框。 我想将文本框与三列alignment。

这是我的代码

<div class="control-group" ng-repeat="oneExt in configAddr.ext"> {{$index+1}}. <input type="text" name="macAdr{{$index+1}}" id="macAddress" ng-model="oneExt.newValue" value=""/> </div> 

最可靠和技术上正确的方法是转换控制器中的数据。 这是一个简单的块function和用法。

 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); 

那么你的看法是这样的:

 <div class="row" ng-repeat="rows in chunkedData"> <div class="span4" ng-repeat="item in rows">{{item}}</div> </div> 

如果在ng-repeat有任何input,那么在数据被修改或提交时,您可能会想要unchunk / rejoin数组。 下面是$watch外观,以便数据始终以原始的合并格式提供:

 $scope.$watch('chunkedData', function(val) { $scope.data = [].concat.apply([], val); }, true); // deep watch 

许多人喜欢用filter来完成这个视图。 这是可能的,但只能用于显示目的! 如果在这个过滤的视图中添加input,将会导致可以解决的问题,但并不美观或可靠

这个filter的问题是每次都返回新的嵌套数组。 Angular正在观看filter的返回值。 filter首次运行时,Angular知道该值,然后再次运行以确保它完成更改。 如果两个值相同,则循环结束。 如果没有,filter会一次又一次地触发,直到它们相同,或者Angular认识到一个无限的摘要循环正在发生并closures。 由于新的嵌套数组/对象之前没有被Angular跟踪过,它总是会看到与之前不同的返回值。 要修复这些“不稳定的”filter,您必须将filter包装在memoize函数中。 lodash有一个memoize函数,lodash的最新版本也包含一个chunk函数,所以我们可以使用npm模块非常简单地创build这个filter,并用webpackwebpack编译脚本。

记住:只显示! 如果使用input,请在控制器中过滤!

安装lodash:

 npm install lodash-node 

创buildfilter:

 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); }); 

这里有一个这个filter的例子:

 <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> 

垂直订购物品

 1 4 2 5 3 6 

关于垂直列(从顶部到底部)而不是水平(从左到右),确切的实现取决于所需的语义。 分配不均的列表可以分配不同的方式。 这里有一个方法:

 <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; } 

然而,获取列最直接,最简单的方法是使用CSS列

 .columns { columns: 3; } 
 <div class="columns"> <div ng-repeat="item in ['a','b','c','d','e','f','g']"> {{item}} </div> </div> 

这个解决scheme非常简单:

JSON:

 [{id:"1",name:"testA"},{id:"2",name:"test B"},{id:"3",name:"test C"},{id:"4",name:"test D"},{id:"5",name:"test E"}] 

HTML:

 <div ng-controller="MyCtrl"> <table> <tr ng-repeat="item in items" ng-switch on="$index % 3"> <td ng-switch-when="0"> {{items[$index].id}} {{items[$index].name}} </td> <td ng-switch-when="0"> <span ng-show="items[$index+1]"> {{items[$index+1].id}} {{items[$index+1].name}} </span> </td> <td ng-switch-when="0"> <span ng-show="items[$index+2]"> {{items[$index+2].id}} {{items[$index+2].name}} </span> </td> </tr> </table> </div> 

在FIDDLE中演示

干净,适应性强的解决scheme, 不需要数据处理

HTML:

 <div class="control-group" class="label" ng-repeat="oneExt in configAddr.ext" ng-class="{'new-row': startNewRow($index, columnBreak) }"> {{$index+1}}. <input type="text" name="macAdr{{$index+1}}" id="macAddress{{$index}}" ng-model="oneExt.newValue" /> </div> 

CSS:

 .label { float: left; text-align: left; } .new-row { clear: left; } 

JavaScript:

 $scope.columnBreak = 3; //Max number of colunms $scope.startNewRow = function (index, count) { return ((index) % count) === 0; }; 

这是一个简单的解决scheme,可以dynamic地将数据呈现到行和列中,而不需要操纵试图显示的数据数组。 另外如果你尝试调整浏览器窗口的大小,你可以看到网格dynamic适应屏幕/格的大小。

(我也为你的id添加了一个{{$ index}}后缀,因为如果你不这样做,ng-repeat会尝试创build多个具有相同ID的元素。)

一个类似的工作例子

m59的答案是相当不错的。 我不喜欢的一点是,它使用div来表示可能是表格的数据。

因此,结合m59的filter(回答上面的地方),这里是如何显示在一个表中。

 <table> <tr class="" ng-repeat="rows in foos | chunk:2"> <td ng-repeat="item in rows">{{item}}</td> </tr> </table> 

以下是一个更简单的方法:

 <table> <tr ng-repeat="item in lists" ng-hide="$index%2!==0"> <td> <label>{{ lists[$index].name}}</label> </td> <td ng-hide="!lists[$index+1]"> <label>{{ lists[$index+1].name}}</label> </td> </tr> </table> 

Cumulo Nimbus的答案对我来说很有用,但是我希望这个网格包含一个div,当列表太长的时候它可以显示滚动条。

为了实现这一点,我添加了style="height:200px; overflow:auto"到表格周围的div,使其显示为单个列。

现在适用于一个数组长度。

我有一个函数,并将其存储在一个服务,所以我可以使用它遍布我的应用程序:

服务:

 app.service('SplitArrayService', function () { return { SplitArray: function (array, columns) { if (array.length <= columns) { return [array]; }; var rowsNum = Math.ceil(array.length / columns); var rowsArray = new Array(rowsNum); for (var i = 0; i < rowsNum; i++) { var columnsArray = new Array(columns); for (j = 0; j < columns; j++) { var index = i * columns + j; if (index < array.length) { columnsArray[j] = array[index]; } else { break; } } rowsArray[i] = columnsArray; } return rowsArray; } } 

});

控制器:

 $scope.rows = SplitArrayService.SplitArray($scope.images, 3); //im splitting an array of images into 3 columns 

标记:

  <div class="col-sm-12" ng-repeat="row in imageRows"> <div class="col-sm-4" ng-repeat="image in row"> <img class="img-responsive" ng-src="{{image.src}}"> </div> </div> 

我的方法是混合的东西。

我的目标是有一个适应屏幕大小的网格。 我想要lg 3列, smmd 2列,以及xs 1列。

首先,我使用angular $window服务创build了以下作用域函数:

 $scope.findColNumberPerRow = function() { var nCols; var width = $window.innerWidth; if (width < 768) { // xs nCols = 1; } else if(width >= 768 && width < 1200) { // sm and md nCols = 2 } else if (width >= 1200) { // lg nCols = 3; } return nCols; }; 

然后,我使用@Cumulo Nimbus提出的课程:

 .new-row { clear: left; } 

在包含ng-repeat的div中,我添加了resizable指令,如本页所述 ,以便每次调整窗口大小时,都会使用新的值更新angular度$window服务。

最终,在重复的div中我有:

 ng-repeat="user in users" ng-class="{'new-row': ($index % findColNumberPerRow() === 0) }" 

请让我知道这种方法的任何缺陷。

希望能有所帮助。

我解决没有.row

 <div class="col col-33 left" ng-repeat="photo in photos"> Content here... </div> 

和CSS

 .left { float: left; } 

这个例子产生一个嵌套的中继器,其中外部数据包括一个内部数组,我想在两列中列出。 这个概念适用于三个或更多列。

在内栏我重复“行”,直到达到极限。 该限制是通过将项目数组的长度除以期望的列数来确定的,在这种情况下是2。 除法方法位于控制器上,并将当前数组长度作为parameter passing。 JavaScript切片(0,array.length / columnCount)函数然后将限制应用于中继器。

然后调用第二列转发器,并重复生成第二列数组后半部分的slice(array.length / columnCount,array.length)。

 <div class="row" ng-repeat="GroupAccess in UsersController.SelectedUser.Access" ng-class="{even: $even, odd: $odd}"> <div class="col-md-12 col-xs-12" style=" padding-left:15px;"> <label style="margin-bottom:2px;"><input type="checkbox" ng-model="GroupAccess.isset" />{{GroupAccess.groupname}}</label> </div> <div class="row" style=" padding-left:15px;"> <div class="col-md-1 col-xs-0"></div> <div class="col-md-3 col-xs-2"> <div style="line-height:11px; margin-left:2px; margin-bottom:2px;" ng-repeat="Feature in GroupAccess.features.slice(0, state.DivideBy2(GroupAccess.features.length))"> <span class="GrpFeature">{{Feature.featurename}}</span> </div> </div> <div class="col-md-3 col-xs-2"> <div style="line-height:11px; margin-left:2px; margin-bottom:2px;" ng-repeat="Feature in GroupAccess.features.slice( state.DivideBy2(GroupAccess.features.length), GroupAccess.features.length )"> <span class="GrpFeature">{{Feature.featurename}}</span> </div> </div> <div class="col-md-5 col-xs-8"> </div> </div> </div> // called to format two columns state.DivideBy2 = function(nValue) { return Math.ceil(nValue /2); }; 

希望这有助于以另一种方式来看解决scheme。 (PS这是我的第一篇文章!:-))

这是一个简单的方法来做到这一点。 这是更多的手动,结束了凌乱的标记。 我不build议这样做,但在某些情况下,这可能是有用的。

这是一个小提琴链接http://jsfiddle.net/m0nk3y/9wcbpydq/

HTML:

 <div ng-controller="myController"> <div class="row"> <div class="col-sm-4"> <div class="well"> <div ng-repeat="person in people = data | limitTo:Math.ceil(data.length/3)"> {{ person.name }} </div> </div> </div> <div class="col-sm-4"> <div class="well"> <div ng-repeat="person in people = data | limitTo:Math.ceil(data.length/3):Math.ceil(data.length/3)"> {{ person.name }} </div> </div> </div> <div class="col-sm-4"> <div class="well"> <div ng-repeat="person in people = data | limitTo:Math.ceil(data.length/3):Math.ceil(data.length/3)*2"> {{ person.name }} </div> </div> </div> </div> </div> 

JS:

 var app = angular.module('myApp', []); app.controller('myController', function($scope) { $scope.Math = Math; $scope.data = [ {"name":"Person A"}, ... ]; }); 

这个设置要求我们在标记上使用一些Math:/,所以你需要通过添加下面这行来注入Math: $scope.Math = Math;

所有这些答案似乎大大超过工程。

到目前为止,最简单的方法是在col-md-4列引导中设置inputdiv,然后由于bootstrap的12列属性,bootstrap会自动将其格式化为3列:

 <div class="col-md-12"> <div class="control-group" ng-repeat="oneExt in configAddr.ext"> <div class="col-md-4"> <input type="text" name="macAdr{{$index}}" id="macAddress" ng-model="oneExt.newValue" value="" /> </div> </div> </div> 
 <div class="row"> <div class="col-md-4" ng-repeat="remainder in [0,1,2]"> <ul> <li ng-repeat="item in items" ng-if="$index % 3 == remainder">{{item}}</li> </ul> </div> </div> 

基于m59的非常好的答案。 我发现如果模型input发生改变,模型input将会模糊,因此您一次只能更改一个字符。 对于任何需要它的人来说,这是一个新的对象列表:

编辑更新,以处理一个页面上的多个filter

 app.filter('partition', function() { var cache = {}; // holds old arrays for difference repeat scopes var filter = function(newArr, size, scope) { var i, oldLength = 0, newLength = 0, arr = [], id = scope.$id, currentArr = cache[id]; if (!newArr) return; if (currentArr) { for (i = 0; i < currentArr.length; i++) { oldLength += currentArr[i].length; } } if (newArr.length == oldLength) { return currentArr; // so we keep the old object and prevent rebuild (it blurs inputs) } else { for (i = 0; i < newArr.length; i += size) { arr.push(newArr.slice(i, i + size)); } cache[id] = arr; return arr; } }; return filter; }); 

这将是用法:

 <div ng-repeat="row in items | partition:3:this"> <span class="span4"> {{ $index }} </span> </div> 

我是bootstrap和angularjs中的新成员,但是这也可以将每4个项目的数组作为一个组,结果几乎就像3列。 这个技巧使用自举断线原则。

 <div class="row"> <div class="col-sm-4" data-ng-repeat="item in items"> <div class="some-special-class"> {{item.XX}} </div> </div> </div> 

Lodash现在有一个内置的块方法,我个人使用: https ://lodash.com/docs#chunk

基于此,控制器代码可能如下所示:

 $scope.groupedUsers = _.chunk( $scope.users, 3 ) 

查看代码:

 <div class="row" ng-repeat="rows in groupedUsers"> <div class="span4" ng-repeat="item in rows">{{item}}</div> </div> 

另一种方式是设定width:33.33%; float:left width:33.33%; float:left这样的包装div:

 <div ng-repeat="right in rights" style="width: 33.33%;float: left;"> <span style="width:60px;display:inline-block;text-align:right">{{$index}}</span> <input type="number" style="width:50px;display:inline-block" "> </div> 

我发现自己也是一个类似的情况,想要生成每个3列的显示组。 但是,虽然我使用bootstrap,但我试图将这些组分成不同的父级div。 我也想做一些有用的东西。

我用ng-repeat方法进行处理如下:

 <div ng-repeat="items in quotes" ng-if="!($index % 3)"> <div ng-repeat="quote in quotes" ng-if="$index <= $parent.$index + 2 && $index >= $parent.$index"> ... some content ... </div> </div> 

这使得更改为不同数量的列变得非常容易,并将其分离为多个父div。

这回答了如何在一列中获得1,2,3的原始问题。 – 由kuppu 14年2月8日在13:47

angularjs代码:

 function GetStaffForFloor(floor) { var promiseGet = Directory_Service.getAllStaff(floor); promiseGet.then(function (pl) { $scope.staffList = chunk(pl.data, 3); //pl.data; // }, function (errorOD) { $log.error('Errored while getting staff list.', errorOD); }); } function chunk(array, columns) { var numberOfRows = Math.ceil(array.length / columns); //puts 1, 2, 3 into column var newRow = []; //array is row-based. for (var i = 0; i < array.length; i++) { var columnData = new Array(columns); if (i == numberOfRows) break; for (j = 0; j < columns; j++) { columnData[j] = array[i + numberOfRows * j]; } newRow.push(columnData); } return newRow; ////this works but 1, 2, 3 is in row //var newRow = []; //for (var i = 0; i < array.length; i += columns) { // newRow.push(array.slice(i, i + columns)); //push effectively does the pivot. array is row-based. //} //return newRow; }; 

查看代码(注:使用引导程序3):

 <div class="staffContainer"> <div class="row" ng-repeat="staff in staffList"> <div class="col-md-4" ng-repeat="item in staff">{{item.FullName.length > 0 ? item.FullName + ": Rm " + item.RoomNumber : ""}}</div> </div> </div>