10

I am working on a site where you can search a food, and see if its a fruit, a vegetable, or neither (because I'm bored). I decided to use Angular, even though I'm pretty new to it. I started getting this error: $rootScope:infdig Infinite $digest Loop

That's may or may not be the exact phrasing or the error, because the page lags out so much, I can't open the Javascript console.

This my result view controller:

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';
                }
            });
        }
    }]);

Heres my app module:

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'
        });
    }]);

And here is layouts/result.html:

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

So I am wondering what could be causing that $digest loop error, or how to find out, because I can't use the console. Thanks!

The whole project is here on Github as well.

2
  • make a plnkr.co Commented Jul 6, 2014 at 3:36
  • A note on style---you should be separating out your http requests into a service. They should not be in the controller. Commented Jul 6, 2014 at 3:51

4 Answers 4

4

The problem that you were having was that you were setting a field on the scope, which implicitly calls $digest and lays out the template again. But, laying out the template makes the http request again, and then changes the scope, which calls $digest. And that is the infinite loop.

You can avoid this by ensuring that the http request never gets triggered during a layout of the template.

A more angular correct way of implementing your app would be to extract your GET request into a proper service and then injecting your service into the controller.

Then in the controller, you make the service call, like this:

app.controller('resultController', ['$scope', '$routeParams', 'whatsitService',
    function($scope, $routeParams, $http) {
        $scope.result = $routeParams.query;
        whatsitService.doit().then(function(result) {
            $scope.whatsit = result;
        }
    })
;

Your template would look like this:

<h1>{{ result }}</h1>
<p>{{ result }} is a {{ whatsit }}</p>
Sign up to request clarification or add additional context in comments.

2 Comments

I updated my code to use service, and I am getting this error: ` Unknown provider: whatIsItProvider <- whatIsIt` I pushed my changes to Github so you can see what I did, its all in the last commit, but I have no idea whats wrong. Do you have any ideas?
And isn't this line: function($scope, $routeParams, $http) { supposed to be this: function($scope, $routeParams, whatsisService) { in your example?
3

The problem is you trying to call a function and publish the return value directly and the value that you are trying to return is out of scope. You need to put that value in scope.

Code snippet:

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';
            }               

        });
    }
}]);

and in the HTML Template:

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

Comments

0

Infinite $digest Loop can happen in this below case if you have bound an expression to it like : {{events()}}

and

$scope.events = function() { return Recording.getEvents(); }

But not in the below case. even if you have bound {{events}}

$scope.events = Recording.getEvents();

The reason is in the first angular suppose the value is changing in every digest loop and it keeps updating it. In second one it simply wait for the promise.

Comments

0

It is happening because of in your angular expression '{{ whatIsIt() }}' in "{{ result }} is a {{ whatIsIt() }}" you are calling a function that returns a different value each time invoke thus causing a new digest cycle which in turn invokes the function.

I think you should bind the result of whatIsIt() to a value and then use that value in template. check this out https://docs.angularjs.org/error/$rootScope/infdig

1 Comment

We'd rather have something you tested and works that thoughts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.