如何使用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,并用webpack
或webpack
编译脚本。
记住:只显示! 如果使用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列, sm
和md
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>