Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

callback after async forEach AngularJS

Tags:

How do I add a callback function after an async forEach Loop?

Here is some better context:

$scope.getAlbums = function(user, callback) {
    $scope.albumsList.forEach(function (obj, i) {
        $scope.getAlbum(user, obj.id, function(value){
            $scope.albums.push(value);
        });
    });
    // callback(); ???
};

$scope.getAlbums('guy123', function(){
    // forEach loop is all done!
    console.log($scope.albums)
});

Controller:

.controller('Filters', ['$scope','Imgur', function($scope, Imgur) {

    $scope.getAlbum = function(user, id, callback) {
        Imgur.album.get({user:user, id:id},    
            function(value) {
                return callback(value.data);
            }
        );
    }

    $scope.getAlbums = function(user, callback) {
        // Callback function at end of this forEach loop?
        // Request is async...
        $scope.albumsList.forEach(function (obj, i) {
            $scope.getAlbum(user, obj.id, function(value){
                $scope.albums.push(value);
            });
        });
    };
)]};

Service:

.factory('Imgur', function($resource) {
    return {
        album : $resource('https://api.imgur.com/3/account/:user/album/:id')
    }
});
like image 487
Dan Kanze Avatar asked May 07 '13 22:05

Dan Kanze


People also ask

What is a callback function in angular?

You can see, the callback function is called when another function is completed. This is a nice feature in an asynchronous environment like Angular ( this is the main usage of a callback in Angular) ! As you can see the callback function is passed as function parameter in Angular !

What is a callback in JavaScript?

JavaScript Callbacks. ❮ Previous Next ❯. "I will call back later!". A callback is a function passed as an argument to another function. This technique allows a function to call another function. A callback function can run after another function has finished.

Why do we need async foreach in foreach?

Another async is needed in the forEach so that we have the list of repos for each user to manipulate. We call it as: This and the promises approach are my favorites since the code is easy to read and change.

Does asyncforeach return a promise?

Then, we can update our example to use our asyncForEach method: We’re getting closer! Actually, our asyncForEach returns a Promise (since it’s wrapped into an async function) but we are not waiting for it to be done before logging ‘Done’. Let’s update our example again to wrap our execution into an async method:


1 Answers

As Andrew said usage of $q and the deferred object should allow you to accomplish your goal.

You want to use $q.all() This will make sure all of your promise objects are resolved and then you can call your call back in .then()

function MyCtrl($scope, $q, $http) {

    $scope.albumsList = [{
            id: 1,
            name: "11"
        }, {
            id: 2,
            name: "22"
        }
    ];
    $scope.albums = [];
    $scope.getAlbum = function(user, id, callback) {
        return $http.get("https://api.imgur.com/3/account/" + user + "/album/" + id).success(
            function(value) {
                return callback(value.data);
            }
        );
    }
    $scope.getAlbums = function (user, callback) {
        var prom = [];
        $scope.albumsList.forEach(function (obj, i) {
            prom.push($scope.getAlbum(user, obj.id, function(value){
                $scope.albums.push(value);
            }));
        });
        $q.all(prom).then(function () {
            callback();
        });
    };
    $scope.getAlbums('guy123', function () {
        alert($scope.albums.length);
    });
}

Example with this on jsfiddle

Works but not with $http calls

With the deferred object you gain access to a promise where you can change successive then() calls together. When you resolve the deferred object it will execute the foreach and then execute your call back function you supplied. I tried to simplify your example a bit further so it would work in jsfiddle.

function MyCtrl($scope, $http, $q) {

    $scope.albumsList = [{
        id: 1,
        name: "11"
    }, {
        id: 2,
        name: "22"
    }];
    $scope.albums = [];
    $scope.getAlbums = function (user, callback) {
        var deferred = $q.defer();
        var promise = deferred.promise;
        promise.then(function () {
            $scope.albumsList.forEach(function (obj, i) {
                $scope.albums.push(obj);
            });
        }).then(function () {
            callback();
        });
        deferred.resolve();
    };
    $scope.getAlbums('guy123', function () {
        alert($scope.albums.length);
    });
}

Example on jsfiddle

A bit more reading on deferred and promises.

like image 138
Mark Coleman Avatar answered Nov 16 '22 19:11

Mark Coleman