简体   繁体   中英

Angular (1) and $scope and async requests

I'm still quite new to Angular (1) and do keep having $scope issues. It's probably very easy to resolve but I can't seem to figure it out myself and keep struggling to keep my $scope updated.

Say I've the following code

.controller('PostsCtrl', function ($scope, $http, $timeout, PostService) {
    $scope.items = [];

    PostService.getAll().then(function(data) {
        var remoteItems = data;

        for (var i = 0; i < remoteItems.length; i++) {
            var object = {};
            object.title = remoteItems[i].title;
            object.id = remoteItems[i]._id;
            $scope.items.push(object);
        }
    });
}) 

As you can see I've created a little service that does make the actual request to my backend. I use a promise and provide a callback function.

Now, because I update $scope.items inside the callback, it doesn't update the $scope inside the controller because of different scopes.

when adding a $scope.$apply I get $digest already in progress error messages in my browser's JavaScript console. This should be solved by wrapping the apply function in a $timeout function. This resolves the error messages but doesn't give me the desired output. I read that when I get these $digest already in progress error messages, the architecture of my application is wrong, though I couldn't find how my architecture should be changed to resolve this.

How can I resolve this? Or better said, what's the best practice to resolve this? I kind of think this is something that happens quite a lot in most Angular applications :) .

I've created a Plunker that's similar to my code, though I do not know how to work around the $http request... Link here: https://plnkr.co/edit/rhWhgCgfV0kA1frM41xL

Thanks for your help in advance!

PostService.getAll().then(function(data) {
    var remoteItems = data;
    var returnedData = [];
    for (var i = 0; i < remoteItems.length; i++) {
        var object = {};
        object.title = remoteItems[i].title;
        object.id = remoteItems[i]._id;
        returnedData.push(object);
    }
    $scope.$apply(function() {
      $scope.items = returnedData;
    });
});

You can use safeApply to avoid "$digest already in progress"

Declaration :

angular.module('yourApp').run(function ($rootScope) {

   /* safe scope apply to avoid "digest already in"
    * $rootScope.$safeApply(fctA());
    * */
   $rootScope.$safeApply = function () {
      var $scope, fn, arg, force = false, args = arguments;
      if (args.length === 1) {
         arg = args[0];
         if (typeof arg === 'function') {fn = arg;} else { $scope = arg; }
      } else if (args.length > 0) {
         $scope = args[0]; fn = args[1];if (args.length === 3) {force = !!args[2]; }
      }
      $scope = $scope || this || $rootScope;
      if ($scope === window) { $scope = $rootScope; }
      fn = fn || function () {};
      if (force || !($scope.$$phase || $scope.$root.$$phase)) {$scope.$apply ? $scope.$apply(fn) : $scope.apply(fn);} else { fn(); }
   };
})

Usage ( don't forget to inject $rootScope in your controllers )

$rootScope.$safeApply(aFunction());
// or 
$rootScope.safeApply( $scope );

EDIT : look at this module also

https://github.com/yearofmoo/AngularJS-Scope.SafeApply

Ugh, I feel stupid but I found the issue. The issue wasn't the callback function. The Plunker proved this. What I didn't recreate was the partial HTML's that I also use in my application.

A closer look on where I included those partials in the main HTML showed that those were out of scope of where I set the controller. To show with code:

<div ng-controller="testController">
    <!-- Do things here -->
</div

<!-- Partials go here -->
<div>
</div>

Is now this:

<div ng-controller="testController">
    <!-- Do things here -->

     <!-- Partials go here -->
     <div>
     </div>
</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM