yevg
yevg

Reputation: 1976

Setting up a listener with $watch in Angular JS

I have a service making two consecutive calls to an API asynchronously.

I would like the app to wait for both to be resolved before proceeding and since one of calls may or may not be made, I believe $watch is the way to go versus nested or chained callbacks.

    var response_complete = {call1:false, call2:false};

    $http.post("myapi.com/slug", data, header).then(function(res){ 

        /* ... */

        response_complete.call1 = true;

    }); 

    if(make_this_call==true){

        $http.post("myapi.com/anotherslug", data, header).then(function(res){ 

            /*...*/

            response_complete.call2 = true;

        }); 

    } else response_complete.call2 = true;

    $scope.$watch("response_complete",function(){

        if(response_complete.call1==true && response_complete.call2==true){

            console.log("DONE!");
        }

    });

So the idea is to create a global variable, and watch it as the two calls complete. The second call, which is conditional, immediately sets it's response variable to true if it is not being made.

But the $watch callback is only fired once and the condition within it (call1 & call2 == true) is never met.

Upvotes: 0

Views: 59

Answers (2)

masterpreenz
masterpreenz

Reputation: 2300

your watch do not work as response complete is not a $scope variable | property:

 // replace this with $scope property declaration
 //var response_complete = {call1:false, call2:false};
 $scope.response_complete = {call1:false, call2:false};

then in your succeeding code use $scope.response_complete to modify its value and so your $watch will be triggered as $scope.response_complete changed.

A better solution:

As others have specified it is better to use $broadcast than $watch, so instead watching the variable throw events instead and catch those event inside your $scope.

$http.post("myapi.com/slug", data, header).then(function() {
    // stuff
    $scope.$broadcast("POST_SLUG_COMPLETE");
});

$http.post("myapi.com/anotherslug", data, header).then(function() {
    // stuff
    $scope.$broadcast("POST_ANOTHERSLUG_COMPLETE");
});

// then in your $scope

$scope.$on("POST_SLUG_COMPLETE", function () {
    // stuff
});

$scope.$on("POST_ANOTHERSLUG_COMPLETE", function () {
    // stuff
});

hope that helps

Upvotes: 1

zameb
zameb

Reputation: 850

If you need your "global" variable for the current scope, you can just do:

$scope.complete = false; 
$http.post("myapi.com/slug", data, header).then(function(res) { 
    $http.post("myapi.com/anotherslug", data, header).then(function(res) { 
        $scope.complete = true;
        console.log("DONE!");
    });
});

You may also use $rootScope for a more "global" value. Other alternatives are $broadcast or a property inside a service.

But more important is to ensure how are you using the async calls. If you want both to be resolved put the second call inside the first. The sample provided by you wouldn't work because response_complete.call1 = true is inside an async thread and it is always false by the time you try to verify it

Upvotes: 0

Related Questions