如何创建没有无限摘要循环的随机/混洗过滤器

时间:2015-05-25 09:43:18

标签: javascript angularjs angularjs-filter

我想要实现以下目标:

  • 能够以随机顺序显示数组中的图像。

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

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>

但是,我收到此错误:

  

未捕获错误:[NG-Modular Error] [$ rootScope:infdig] 10 $ digest()   迭代达成。中止!观察者在最近5次迭代中被解雇:   [[{ “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);
        };

那么解决方案是什么?

1 个答案:

答案 0 :(得分:1)

要修复无限摘要,您需要将过滤器包装在memoize函数中。解决问题的最佳方法是从knuth-shuffle安装lodashnpm,然后使用您喜欢的任何模块系统来创建过滤器。这个例子是使用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();
};