Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/472.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Angular.js包含ng重复和过滤器的有限摘要循环_Javascript_Angularjs_Loops_Infinite_Digest - Fatal编程技术网

Javascript Angular.js包含ng重复和过滤器的有限摘要循环

Javascript Angular.js包含ng重复和过滤器的有限摘要循环,javascript,angularjs,loops,infinite,digest,Javascript,Angularjs,Loops,Infinite,Digest,我在angularjs中创建了一个自定义过滤器,它按日期对元素进行分组 这是HTML部分: <table ng-repeat="(index, groupData) in something = (recentTasks | groupBy:dataGroupBy) track by $index"> 它的作用-输入(recentTasks)是一个任务数组。每个任务都定义了一个“日期”参数。我需要按日期将这些任务分开-每天将在单独的表中。它是有效的,但我得到了无限的摘要循环 你能帮

我在angularjs中创建了一个自定义过滤器,它按日期对元素进行分组

这是HTML部分:

<table ng-repeat="(index, groupData) in something = (recentTasks | groupBy:dataGroupBy) track by $index">
它的作用-输入(recentTasks)是一个任务数组。每个任务都定义了一个“日期”参数。我需要按日期将这些任务分开-每天将在单独的表中。它是有效的,但我得到了无限的摘要循环

你能帮我解决我的问题吗?还是有更好的解决方案

编辑: 输入和输出示例:

$scope.items = [
    {name: 'Abc', date: '2014-03-12'},
    {name: 'Def', date: '2014-03-13'},
    {name: 'Ghi', date: '2014-03-11'},
    {name: 'Jkl', date: '2014-03-12'}
]
输出必须按如下方式分组:

module.filter('groupBy', function () {
    return function(items, field) {
        var groups = [];

        switch (field) {
            case 'week':
                angular.forEach(items, function(item) {
                    var parsed = parseDateTime(item.date);
                    var date = new Date(parsed.year, parsed.month - 1, parsed.day);
                    var back = calculateWeeksBack(date);

                    if (groups[back] == undefined)
                    {
                        groups[back] = {
                            time_back: calculateWeeksBack(date),
                            tasks: []
                        };
                    }

                    groups[back].tasks.push(item);
                    groups[back].total_time += item.time;
                });

                break;

            case 'month':
                angular.forEach(items, function(item) {
                    var parsed = parseDateTime(item.date);
                    var date = new Date(parsed.year, parsed.month - 1, parsed.day);
                    var back = calculateMonthsBack(date);

                    if (groups[back] == undefined)
                    {
                        groups[back] = {
                            time_back: calculateMonthsBack(date),
                            tasks: []
                        };
                    }

                    groups[back].tasks.push(item);
                    groups[back].total_time += item.time;
                });

                break;

            default:
                angular.forEach(items, function(item) {
                    var parsed = parseDateTime(item.date);
                    var date = new Date(parsed.year, parsed.month - 1, parsed.day);
                    var back = calculateDaysBack(date);

                    if (groups[back] == undefined)
                    {
                        groups[back] = {
                            time_back: calculateDaysBack(date),
                            tasks: []
                        };
                    }

                    groups[back].tasks.push(item);
                    groups[back].total_time += item.time;
                });
        }
        return groups;
    }
});
[
    '2013-03-11': [
        {name: 'Ghi'}
    ],
    '2013-03-12': [
        {name: 'Abc'},
        {name: 'Jkl'}
    ],
    '2013-03-13': [
        {name: 'Def'}
    ]
]
$scope.prop1 = Math.random();
$scope.prop2 = Math.random();

$scope.$watch('prop1', function() {
  $scope.prop2 = Math.random();
});
$scope.$watch('prop2', function() {
  $scope.prop1 = Math.random();
});
因为每天的项目都在HTML结构中的单独表格中

<table ng-repeat="dayData in groupBy(items, 'day')">
    <thead>
        <tr><td>{{ dayData.date }}</td> </tr>
    </thead>
    <tbody>
        <tr ng-repeat="item in dayData.items">
            <td>{{ item.name }}</td>
        </tr>
    </tbody>
</table>

{{dayData.date}
{{item.name}

要理解为什么会发生这种情况,您需要了解摘要周期。Angular基于“脏检查”,摘要周期是Angular迭代作用域上的所有属性以查看哪些属性已更改。如果任何属性发生了更改,它将触发这些属性的所有监视,以让它们知道发生了什么。由于手表可以改变示波器的属性,Angular会在手表完成后进行另一轮脏检查。当对所有属性进行迭代并且发现它们都没有更改时,摘要循环停止。当手表总是为属性设置新值时,就会出现无限摘要。类似这样的解释可能更好:

$scope.myNumber = Math.random();
$scope.$watch('myNumber', function() {
  $scope.myNumber = Math.random();
});
也就是说,我们的手表永远不会停止被调用,因为它总是改变myNumber的值。另一个常见的错误原因是当您有两个属性和两个手表时,如下所示:

module.filter('groupBy', function () {
    return function(items, field) {
        var groups = [];

        switch (field) {
            case 'week':
                angular.forEach(items, function(item) {
                    var parsed = parseDateTime(item.date);
                    var date = new Date(parsed.year, parsed.month - 1, parsed.day);
                    var back = calculateWeeksBack(date);

                    if (groups[back] == undefined)
                    {
                        groups[back] = {
                            time_back: calculateWeeksBack(date),
                            tasks: []
                        };
                    }

                    groups[back].tasks.push(item);
                    groups[back].total_time += item.time;
                });

                break;

            case 'month':
                angular.forEach(items, function(item) {
                    var parsed = parseDateTime(item.date);
                    var date = new Date(parsed.year, parsed.month - 1, parsed.day);
                    var back = calculateMonthsBack(date);

                    if (groups[back] == undefined)
                    {
                        groups[back] = {
                            time_back: calculateMonthsBack(date),
                            tasks: []
                        };
                    }

                    groups[back].tasks.push(item);
                    groups[back].total_time += item.time;
                });

                break;

            default:
                angular.forEach(items, function(item) {
                    var parsed = parseDateTime(item.date);
                    var date = new Date(parsed.year, parsed.month - 1, parsed.day);
                    var back = calculateDaysBack(date);

                    if (groups[back] == undefined)
                    {
                        groups[back] = {
                            time_back: calculateDaysBack(date),
                            tasks: []
                        };
                    }

                    groups[back].tasks.push(item);
                    groups[back].total_time += item.time;
                });
        }
        return groups;
    }
});
[
    '2013-03-11': [
        {name: 'Ghi'}
    ],
    '2013-03-12': [
        {name: 'Abc'},
        {name: 'Jkl'}
    ],
    '2013-03-13': [
        {name: 'Def'}
    ]
]
$scope.prop1 = Math.random();
$scope.prop2 = Math.random();

$scope.$watch('prop1', function() {
  $scope.prop2 = Math.random();
});
$scope.$watch('prop2', function() {
  $scope.prop1 = Math.random();
});
这些手表将以无休止的循环相互触发

因此,在您的情况下,过滤器总是返回一个包含新对象的新数组。Angular不会通过检查所有属性并进行比较来比较对象,相反,它会添加一个
$$hashkey
属性,并使用该属性与其他对象进行比较。如果两个对象具有相同的
$$hashkey
属性,则认为它们相等。所以,即使每次都返回相同的数据结构,Angular也会将其视为一个新对象,并运行另一个摘要循环,直到它放弃为止

因此,为了使过滤器正常工作,您需要更改代码,以便对于传入的相同参数,它返回一个具有相同对象的数组,如中所示,对这些对象的引用相同。它应该足以确保您不总是为组[返回]创建新对象,而是重用以前的对象

编辑:

好吧,我要让你失望,我建议你重新考虑你的过滤器。对于其他开发人员(或者一年后的您自己)来说,您在
ng repeat
上有一个过滤器,它不返回要重复的列表子集,而是一个新的数据结构,这将有点让人困惑。举个例子:

// Controller
$scope.items = [
  {name: 'Buy groceries', time: 10},
  {name: 'Clean the kitchen', time: 20}
];

// Template
<li ng-repeat="item in items | groupBy:something">
  {{item.total_time}}
</li>

这就不那么令人困惑了,因为很明显,
groupBy()
方法返回一个新的数据结构。它还将为您修复无限摘要错误。

有两种方法可以解决此问题:

  • 对数组的每个元素使用$$hashKey属性。 Angular不会通过检查所有属性并进行比较来比较对象,而是添加$$hashkey属性并使用该属性与其他对象进行比较。如果两个对象具有相同的$$hashkey属性,则认为它们相等。所以,即使每次都返回相同的数据结构,Angular也会将其视为一个新对象,并运行另一个摘要循环,直到它放弃为止。 见:

    • 老把戏$digest问题-jsfiddle.net/LE6Ay

    • 添加了$$hashKey属性-jsfiddle.net/LE6Ay/1

  • 不要在每次getList()调用中创建新对象。正确的解决方案是使用稳定模型,这意味着将数组分配给作用域/控制器,而不是使用getter

  • 将告诉您不要在ngRepeat中每次调用函数时都创建新的可变对象,因为摘要循环将在确定该对象是否为稳定模型之前多次检查该对象是否相同,并且每个新调用将创建一个等效但不相同的对象。正如其他人提到的,“正确的解决方案是使用稳定的模型,这意味着将数组分配给作用域/控制器,而不是使用getter。”我在使用嵌套的ngRepeats时遇到了这个问题,这使得在没有getter的情况下很难做到这一点

    我找到的最简单的解决方案是使用ngInit初始化一个变量以引用函数调用的结果,然后使用ngRepeat遍历该稳定变量。例如:

    <div ng-init="issues=myCtrl.getUniqueIssues()">
        <div ng-repeat="issue in issues">{{issue.name}}</div>
    </div>
    
    
    {{issue.name}
    

    我的资料来源还有一个过滤器示例:

    感谢您的解释,现在我明白了为什么会出现错误。但我仍然不知道,如何解决它。你能多帮我一点忙吗?谢谢转发!非常感谢你的回答!实际上,我真的不知道如何在不改变结构的情况下做到这一点。问题是,在我的输入中(“项”)是未排序的任务。在输出中,我需要对任务进行排序和分组。我已经在我的第一篇文章中添加了一些示例。你现在能帮我找到解决办法吗?