Pregunta

I decided to start learning AngularJS by making a simple app.

The server-side application is built with ExpressJs, but the resource used below (/movie/:id) are not implemented yet, so pointing to this URL will result in a 404 (Not Found) error. So only getting '/' works.

I wanted to see how a $resource behaved so I made this simple test :

var app = angular.module("app", ["ngResource"]);

app.factory("Movie", function ($resource) {
    return $resource("/movie/:id");
})

app.controller("MovieCtrl", function($scope, Movie) {
    $scope.test = function () {
        Movie.query();
        return 42;
    } 
});

And my template file :

<div ng-app="app">
    <div ng-controller="MovieCtrl">
        {{ test() }}
    </div>
</div>

As expected the template is rendered and '42' is properly displayed, but if I watch the console in the Chrome developer tools I keep seeing the following error (also as expected):

GET http://localhost/movie 404 (Not Found)

But this message is printed indefinitely and never stops, as if my Movie resource keeps trying to reach /movie even though after a hundred tries it still keeps failing.

Thank you in advance.

¿Fue útil?

Solución

This is because Movie.query() calls $scope.$apply() after it gets response from the server.

Everytime $scope.$apply() is called, angular does dirty checking (which again invokes test and therefore calls Movie.query() again) to find out if anything has changed. This causes an infinite loop.

move Movie.query() out from the test(), and this should work.

Let me make myself clear - take look at this pseudo code:

var watches = ['$scope.test()'];
var previous = {};
var values = {};

$rootScope.$apply = function(){
  previous = values;
  values = {};
  var dirty = false;  
  for (var i =0;i<watches.length;i++){
      var expression = watches[i];
      values[expression] = value = eval(expression);
      if(value!=previous)dirty=true;
  }
  if(dirty)$rootScope.$apply();
}

Movie.query = function(){
   setTimeout(function(){
      $rootScope.$apply();
   },300);
}

$scope.test = function(){
   Movie.query();
   return 42;
}

so the flow is following:

  1. $scope.apply();
  2. $scope.test();
  3. Movie.query(); -> setTimeout($scope.apply,100) (back to beginning );

and so on..

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top