1

我想在由 AngularJS 提供支持的应用程序中使用 twitter Bootstrap。我开始使用 Scaffolding http://twitter.github.com/bootstrap/scaffolding.html#gridSystem进行网格布局并遇到以下问题:

根据 Bootstrap 上的文档和示例,网格布局必须遵循以下结构:

<div class="row">
    <div class="span4">...</div>
    <div class="span8">...</div>
</div>
<div class="row">
    <div class="span4">...</div>
    <div class="span8">...</div>
</div>

...

这意味着具有“跨度”类(列)的标签必须是具有“行”类(行)的标签的子元素。

在我的应用程序中,我有一个简单的对象数组 - 项目,我想在每一行中显示为 3 个项目。当然,我不知道我必须展示的项目数量。据我了解,这种结构需要两个嵌套循环 - 一个用于行,一个用于列,如果我的模型是二维数组但我不想更改我的模型(项目)以适应看法。我最终做的是使用过滤器将模型更改为二维数组,然后使用嵌套的 ngRepeat 创建列:http: //jsfiddle.net/oburakevych/h4puc/11/

它似乎按预期工作,但我在调试控制台中遇到错误:

Error: 10 $digest() iterations reached. Aborting!

据我了解,嵌套的 ng-repeat 的摘要正在触发外部 ng-repeat 的摘要?任何人都可以提出正确的实施方式吗?

4

1 回答 1

3

这里的问题是,当您使用ng-repeatAngular 时,会为列表表达式创建一个监视,它是您的项目数组和过滤器的组合。当 Angular 运行一个摘要时,它会一直调用那个 watch,直到表达式的值不再改变。而且由于您的过滤器总是创建一个新数组,因此每次调用它时值都会发生变化,并且 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>

如果您仍想为此使用过滤器,则必须在过滤器内实现缓存,以确保在使用相同参数调用过滤器时始终返回相同的数组引用。但这是一个滑坡,因为您需要使该缓存无效以避免内存泄漏。

于 2013-03-08T08:46:42.600 回答