如何在没有无限摘要循环的情况下创建 random/shuffle 过滤器

How to create random/shuffle filter without infinite digest loop

我想实现以下目标:

为了解决这个问题,我决定创建一个过滤器:

var app = angular.module('app');
app. filter('randomizer', randomizer);


 function randomizer() {

        return function (collection, defaultValue) {

            var result = defaultValue;

            if (!!collection) {
                if (Array.isArray(collection) && collection.length === 1) {
                    result = collection[0] || defaultValue;
                } else if (!Array.isArray(collection)) {
                    result = collection || defaultValue;
                } else {
                    // randomize here please
                    var idx = parseInt(((Math.random()) * collection.length));
                    result = collection[idx] || defaultValue;
                }
            }

            return result;
        }
    }

现在在模板中,我调用为:

<div class="masonry-pin masonry-brick" ng-repeat="p in vm.list | orderBy: 'updatedAt':true">

     <img ng-src="{{vm.baseUrl + 'documents/view/' + ( p.documents | randomizer:{id: 'notfound'}:p.id).id }}">

</div>

但是,我收到此错误:

Uncaught Error: [NG-Modular Error] [$rootScope:infdig] 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [[{"msg":"fn: expressionInputsWatch","newVal":"http://localhost:3002/documents/view/158","oldVal":"http://localhost:3002/documents/view/159"},{"msg":"fn:

经过一些研究,我发现它与值变化有关,但我正在改变我的值。

现在我可以理解范围正在发生变化。但是,我注意到即使我有一个像这样的简单过滤器:{{p.documents |控制台}}

并且控制台过滤器只获取一个数组并在控制台中打印。

现在当列表中有 10 个对象时,它会调用过滤器 30 次。

这里是控制台过滤器的样子,但是对于 10 个项目它调用了 66 次。

为什么 ??

app.filter('console', pipeConsole);

function pipeConsole() {


        return function (value, o) {
            print(value);
            print(o);
            print(count);

        }

        function print(o) {
            if (!!o) {
                console.log(o);
            }
            else if (o === null) {
                console.warn(o);
            }
        }
    };

这里我什至没有返回不同的值...(如果我按照这里解释的逻辑 - Angular: infinite digest loop in filter

即使不是过滤器,也会导致这个问题

现在我已经创建了一个服务功能,但我遇到了这个问题。

 <img ng-src="{{vm.baseUrl + 'documents/view/' + vm.random( p.documents , {id: 'notfound'}).id }}">


vm.random = function (a, s) {

            return utility.randomizer(a, s);
        };

那么解决方法是什么?

要修复无限摘要,您需要将过滤器包装在 memoize 函数中。解决问题的最佳方法是从 npm 安装 knuth-shufflelodash,然后使用您喜欢的任何模块系统来创建过滤器。这个例子是 CommonJS/browserify.

var memoize = require('lodash/function/memoize');
var shuffle = require('knuth-shuffle');

app.filter('shuffle', function() {
  return memoize(shuffle);
});

以这种方式创建过滤器时,如果将空值传递给 shuffle 函数,您可能会遇到问题。在那种情况下,只需添加一个检查:

app.filter('shuffle', function() {
  return memoize(function(input) {
    if (input === undefined) { return; }
    return shuffle.apply(null, arguments);
  });
});

您可以从 this answer 了解更多关于无限摘要问题的信息。

要重新打乱列表,您可以将任意 $scope 属性 传递给过滤器,然后在您想要重新打乱时更改 属性。递增数字或使用 Math.random() 是执行此操作的好方法。这是有效的,因为结果是根据传递的参数缓存的,所以传递一个无用的参数会产生一个新的结果。

myList | shuffle:whatever
$scope.whatever = 0;
$scope.reshuffle = function() {
  ++$scope.whatever;
  // OR
  $scope.whatever = Math.random();
};