Angular 无限 $digest 循环

10

我正在制作一个网站,你可以在上面搜索食物,并查看它是水果、蔬菜还是其他(因为我很无聊)。虽然我对Angular不太熟悉,但我决定使用它。

然后我开始遇到这个错误:$rootScope:infdig Infinite $digest Loop

由于页面卡顿,我无法打开Javascript控制台,所以这可能并不是错误的精确措辞。

这是我的结果视图控制器:

app.controller('resultController', ['$scope', '$routeParams', '$http',
    function($scope, $routeParams, $http) {
        $scope.result = $routeParams.query;

        $scope.whatIsIt = function() {
            $http.get('json/foods.json').success(function(data) {
                var lists = JSON.parse(data);
                var itIsA = 'uuggghhhhh';

                if (lists['fruit'].contains($scope.result)) {
                    itIsA = 'fruit';
                } else if (lists['vegetable'].contains($scope.result)) {
                    itIsA = 'vegetable';
                }
            });
        }
    }]);

这是我的应用程序模块:

var app = angular.module('fruitOrNot', [
    'ngRoute'
]);

app.config(['$routeProvider' ,
    function($routeProvider) {
        $routeProvider.when('/', {
            templateUrl: 'layouts/fruit-search.html',
            controller: 'searchController'
        }).when('/:query', {
            templateUrl: 'layouts/result.html',
            controller: 'resultController'
        });
    }]);

这里是layouts/result.html:

<h1>{{ result }}</h1>
<p>{{ result }} is a {{ whatIsIt() }}</p>

我在想是什么导致了那个 $digest 循环错误,或者如何找出原因,因为我无法使用控制台。谢谢!

整个项目也可以在 Github 上找到:https://github.com/INOVA-Technology/isitafruitoravegetable.com


创建一个 http://plnkr.co/。 - Mosho
关于编程风格的说明---你应该将你的http请求分离成一个服务。它们不应该在控制器中。 - Andrew Eisenberg
好的,谢谢,我会这样做。 - Addison
4个回答

4
你所遇到的问题是在作用域上设置字段,这会隐式调用$digest并重新布局模板。但是,重新布局模板会再次发出http请求,然后更改作用域,进而调用$digest。这就是无限循环。
你可以通过确保模板布局期间不触发http请求来避免这种情况。
更加angular正确的实现方式是将GET请求提取为适当的服务,然后将该服务注入到控制器中。
然后在控制器中,像这样调用服务:
app.controller('resultController', ['$scope', '$routeParams', 'whatsitService',
    function($scope, $routeParams, $http) {
        $scope.result = $routeParams.query;
        whatsitService.doit().then(function(result) {
            $scope.whatsit = result;
        }
    })
;

您的模板将如下所示:

您的模板将如下所示:

<h1>{{ result }}</h1>
<p>{{ result }} is a {{ whatsit }}</p>

我更新了我的代码以使用服务,但是我遇到了这个错误:Unknown provider: whatIsItProvider <- whatIsIt。我将更改推送到Github,所以您可以看到我所做的一切,都在最后一次提交中,但我不知道出了什么问题。你有什么想法吗? - Addison
2
这一行不应该是 function($scope, $routeParams, whatsisService) { 吗?在你的例子中。 - Addison

3
问题在于你试图调用一个函数并直接发布返回值,而你试图返回的值超出了作用域范围。你需要将该值放入作用域内。
代码片段:
app.controller('resultController', ['$scope', '$routeParams', '$http',
function($scope, $routeParams, $http) {
    $scope.result = $routeParams.query;
    $scope.itIsA = "";
    $scope.whatIsIt = function() {
        $http.get('json/foods.json').success(function(data) {
            var lists = JSON.parse(data);
            var itIsA = 'uuggghhhhh';

            if (lists['fruit'].contains($scope.result)) {
                $scope.itIsA = 'fruit';
            } else if (lists['vegetable'].contains($scope.result)) {
                $scope.itIsA = 'vegetable';
            }               

        });
    }
}]);

在HTML模板中:

p>{{ result }} is a {{itIsA}}</p>

0

这是因为在你的 Angular 表达式 '{{ whatIsIt() }}' 中,你调用了一个每次返回不同值的函数,从而导致新的脏检查循环,进而调用该函数。

我认为你应该将 whatIsIt() 的结果绑定到一个值上,然后在模板中使用该值。请查看 https://docs.angularjs.org/error/$rootScope/infdig


我们更愿意拥有经过测试并且可行的东西,而不是想法。 - J. Chomel

0
在下面的情况下,如果您将表达式绑定到它上面,例如:{{events()}},则可能会发生无限$digest循环。
而且 $scope.events = function() { return Recording.getEvents(); } 但在下面的情况下不会发生。即使您已经绑定了{{events}} $scope.events = Recording.getEvents(); 原因是在第一个Angular中,假设值在每个digest循环中都在变化,并且它会不断更新它。在第二个Angular中,它只是等待承诺。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接