我想在我的应用程序AngularJS上使用twitter Bootstrap。我开始使用Scaffolding http://twitter.github.com/bootstrap/scaffolding.html#gridSystem进行网格布局,并遇到以下问题:
根据Bootstrap上的文档和示例,Grid布局必须遵循以下结构:
<div class="row">
<div class="span4">...</div>
<div class="span8">...</div>
</div>
<div class="row">
<div class="span4">...</div>
<div class="span8">...</div>
</div>
...
意味着带有'span'类(列)的标记必须是带有'row'类(行)的标记的子元素。
在我的应用程序中,我有一个简单的对象数组 - 项目,我想在每一行显示为3个项目。 Offcourse我不知道我必须显示的项目数量。 据我所知,这种结构需要两个嵌套循环 - 一个用于行,一个用于列,如果我的模型是一个二维数组,它将完美地工作,但我不想改变我的模型(项目)以适应视图。我最终做的是使用过滤器将模型更改为二维数组,然后使用嵌套的ngRepeat创建列:http://jsfiddle.net/oburakevych/h4puc/11/
它似乎按预期工作,但我在调试控制台中遇到错误:
Error: 10 $digest() iterations reached. Aborting!
根据我的理解,嵌套的ng-repeat的摘要是在外部ng-repeat上触发消化?任何人都可以建议一种正确的方法来实现这个吗?
答案 0 :(得分:3)
这里的问题是当你使用ng-repeat
时,Angular会为列表表达式创建一个监视表,它是项目数组和过滤器的组合。当Angular运行摘要时,它会一直调用该监视,直到表达式的值不再发生变化。由于您的过滤器总是创建一个新数组,因此每次调用时值都会更改,并且Angular会陷入无限循环。因此,您的代码基本上与执行此操作相同:
$scope.myList = [];
$scope.$watch('myList', function() {
$scope.myList = [];
});
通过监视范围,您可以告诉Angular按值而不是引用进行比较,以避免无休止的摘要问题,如下所示:
$scope.myList = [];
$scope.$watch('myList', function() {
$scope.myList = [];
}, true); // Passing true as the last argument triggers comparison by value instead
但在你的情况下这是不可能的。因此,最好只在需要时将项目数组拆分为更小的数组,如下所示:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
<script>
angular.module('myApp', []).controller('Ctrl', function($scope) {
$scope.projects = [
{name: 'My Project 1'},
{name: 'My Project 2'},
{name: 'My Project 3'},
{name: 'My Project 4'},
{name: 'My Project 5'},
{name: 'My Project 6'}
];
var splitIntoRows = 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.$watch('projects', function() {
$scope.projectRows = splitIntoRows($scope.projects, 3);
});
});
</script>
</head>
<body ng-controller="Ctrl">
<ul class="row" ng-repeat="projectRow in projectRows">
<li class="span4" ng-repeat="project in projectRow">
{{project.name}}
</li>
</ul>
</body>
</html>
如果您仍想为此使用过滤器,则必须在过滤器内部实现缓存,以确保在使用相同参数调用过滤器时始终返回相同的数组引用。但这是一个滑坡,因为你需要使缓存无效以避免内存泄漏。