【问题标题】:Why filters changing elements on arrays doesn't works on Angular?为什么过滤器更改数组上的元素在 Angular 上不起作用?
【发布时间】:2014-06-13 18:33:50
【问题描述】:

我确定我做错了什么,但即使在 Angular.js 上调试我也找不到错误

我在这里学习 Angular 基础教程:https://docs.angularjs.org/tutorial/step_03 教程中的所有示例都可以正常工作。 但是我想尝试一些很酷的功能,并自己在第 3 步的示例中添加了代码

索引.html: https://gist.github.com/tario/f07239992eea75535421

controller.js https://gist.github.com/tario/1b6155b5c97e747abe32

过滤器在这里定义:https://gist.github.com/tario/1b6155b5c97e747abe32#file-controllers-js-L16

只要我使用复选框启用大写,就会产生以下错误:

错误:[$rootScope:infdig] 达到了 10 个 $digest() 迭代。中止! 观察者在最后 5 次迭代中触发: [["fn: $watchCollectionWatch; newVal: 62; oldVal: 59"],["fn: $watchCollectionWatch; newVal: 65; oldVal: 62"],["fn: $watchCollectionWatch; newVal: 68; oldVal: 65"],["fn: $watchCollectionWatch; newVal: 71; oldVal: 68"],["fn: $watchCollectionWatch; newVal: 74; oldVal: 71"]] http://errors.angularjs.org/1.2.17/$rootScope/infdig?p0=10&p1=%5B%5B%22fn%3…20%24watchCollectionWatch%3B%20newVal%3A%2074%3B%20oldVal%3A%2071%22%5D%5D 在http://xxxxxxx.doesntexists.com:8000/app/bower_components/angular/angular.js:78:12 在 Scope.$get.Scope.$digest (http://xxxxxxx.doesntexists.com:8000/app/bower_components/angular/angular.js:12396:19) 在 Scope.$get.Scope.$apply (http://xxxxxxx.doesntexists.com:8000/app/bower_components/angular/angular.js:12622:24) 在 HTMLInputElement。 (http://xxxxxxx.doesntexists.com:8000/app/bower_components/angular/angular.js:17016:11) 在http://xxxxxxx.doesntexists.com:8000/app/bower_components/angular/angular.js:2810:10 在 Array.forEach (本机) 在 forEach (http://xxxxxxx.doesntexists.com:8000/app/bower_components/angular/angular.js:320:11) 在 HTMLInputElement.eventHandler (http://xxxxxxx.doesntexists.com:8000/app/bower_components/angular/angular.js:2809:5)

我不知道以这种方式进行过滤是否是最佳做法,但我想知道为什么会失败,因为我唯一要做的就是使用另一个数组的转换内容创建一个新数组,没关系???

【问题讨论】:

  • 如果我的回答对您有用,欢迎采纳。否则,如果您对它有任何疑问,我很乐意对其进行编辑。

标签: javascript angularjs angularjs-scope


【解决方案1】:

正如 Angular 文档中提到的 error

当应用程序的模型变得不稳定并且 每个 $digest 循环都会触发状态更改和后续的 $digest 循环。 Angular 检测到这种情况并防止无限循环 以免导致浏览器无响应。

在每个摘要周期,您的过滤器都会返回一个新数组,并且由于 AngularJS 通过脏检查进行监视,它会触发一个新的摘要周期,因为您的过滤器发送的新值与之前发送的不同。

我看到两种方法可以解决您的问题:

1) 如果使用Lodashmemoize函数给定相同的参数,则发送相同的对象。

在每次调用 memoized 函数时,解析器(提供给 memoize 的第二个函数)将在缓存中查找结果是否存储(默认情况下,解析器返回转换为字符串的第一个参数附加了一些乱码)。如果找到结果,则返回。否则,计算函数并将返回值存储在缓存中。

    phonecatApp.filter('uppercaseAllThings', function () {
        return _.memoize(
        function (items, enabled) {
            if (enabled) {
                var newitems = [];
                angular.forEach(items, function (item) {
                    newitems.push(uppercaseAllAttributes(item));
                });

                return newitems;
            }
            return items;
        },
        function (items, enabled) {
            return enabled + angular.toJson(items)
        });
    });

解释这个解决方案的 JsFiddle 可以在 here 找到。

2) 如果你想要的只是将值设置为大写,你可以使用 CSS 通过条件应用一个 CSS 类来完成这项工作。

我们将有条件应用的 CSS 类将使用 text-transform property

.uppercase {
   text-transform:uppercase;
}

这个类必须添加到你的样式表中。

而 HTML 将从

更改
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp | uppercaseAllThings:uppercaseEnabled">
   <span>{{phone.name}}</span>
   <p>{{phone.snippet}}</p>
</li>

<li ng-repeat="phone in phones | filter:query | orderBy:orderProp"
    ng-class="{'uppercase':uppercaseEnabled}">
   <span>{{phone.name}}</span>
   <p>{{phone.snippet}}</p>
</li>

我做了一个简单的JSFiddle 解释第二种解决方案。

【讨论】:

    猜你喜欢
    • 2012-05-11
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2021-07-30
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多