Rani Radcliff
Rani Radcliff

Reputation: 5084

Angular Then doesn't trigger for Promise on Recursive Function

Just when I thought I had promises figured out, I'm stumped again. I am trying to use a recursive function to return a promise. It looks like it is working but the "then" portion never gets hit. I tried using $q.all but that is causing me a problem with multiple calls to my Web API. Rewriting the code to use recursion seemed like the answer, but I cannot get the "then" to execute. I figure that I must be missing something simple but I can't seem to figure out just what.

Here is the call to the function:

                    getClusterLink(linkcodes, returnString)
                    .then(function () {
                        value.vchTextBeforeQuestionCluster = $scope.returnString;

                    })

Here is the recursive function:

    function getClusterLink(linkcodes, returnString) {
    var deferred = $q.defer();
    $scope.returnString = returnString;
    if (linkcount < linkcodes.length) {
        contractorService.gethyperlink(linkcodes[linkcount])
        .success(function (data) {
            var vchUrl = data[0].vchUrl;
            var end = vchUrl.length;
            var docID = vchUrl.substring(vchUrl.indexOf("=") + 1, end);
            var vchLinkName = data[0].vchLinkName;
            var yay = '<a href="" ng-click="getDocumentByID(' + docID + ')">' + vchLinkName + '</a>';
            var yCode = "|Y" + linkcodes[linkcount] + "~";
            $scope.returnString = $scope.returnString.replaceAll(yCode, yay);
            linkcount++;

            return getClusterLink(linkcodes, $scope.returnString);
        })

    }
    else {
        deferred.resolve();
        return deferred.promise;
    }
};

The function itself works correctly. It hits the resolve and the return deferred.promise, but the "then" never fires.

Any assistance is greatly appreciated!

Upvotes: 0

Views: 425

Answers (3)

Rani Radcliff
Rani Radcliff

Reputation: 5084

I figured it out. Seems the problem was that I had var deferred = $q.defer() inside of the recursive function so it kept resetting the variable. Moving it outside of the function (like below) resolved the issue and the "then" now fires.

   var thisdeferred = $q.defer();

function getClusterLink(linkcodes, returnString) {

    if (linkcount < linkcodes.length) {
        contractorService.gethyperlink(linkcodes[linkcount])
        .success(function (data) {
            var vchUrl = data[0].vchUrl;
            var end = vchUrl.length;
            var docID = vchUrl.substring(vchUrl.indexOf("=") + 1, end);
            var vchLinkName = data[0].vchLinkName;
            var yay = '<a href="" ng-click="getDocumentByID(' + docID + ')">' + vchLinkName + '</a>';
            var yCode = "|Y" + linkcodes[linkcount] + "~";
            $scope.returnString = $scope.returnString.replaceAll(yCode, yay);
            linkcount++;
            return getClusterLink(linkcodes, $scope.returnString);
        })


    }
    else {
        thisdeferred.resolve();
    }
    return thisdeferred.promise;

};

Upvotes: 1

Bergi
Bergi

Reputation: 664538

Your getClusterLink function does not return a promise in the case where contractorService.gethyperlink is called. I wonder you don't get an exception from that. And even if you always returned deferred.promise, it wouldn't be resolved in that branch.

But you should not use a deferred at all here. Just use $q.resolve, and chain onto the $http promise that gethyperlink returns. Notice that .success is deprecated, and does no chaining like then does - returning from that callback is pointless.

function getClusterLink(linkcodes, returnString) {
    $scope.returnString = returnString;
    if (linkcount < linkcodes.length) {
        return contractorService.gethyperlink(linkcodes[linkcount])
//      ^^^^^^
        .then(function (data) {
//      ^^^^^
            var vchUrl = data[0].vchUrl;
            var end = vchUrl.length;
            var docID = vchUrl.substring(vchUrl.indexOf("=") + 1, end);
            var vchLinkName = data[0].vchLinkName;
            var yay = '<a href="" ng-click="getDocumentByID(' + docID + ')">' + vchLinkName + '</a>';
            var yCode = "|Y" + linkcodes[linkcount] + "~";
            $scope.returnString = $scope.returnString.replaceAll(yCode, yay);
            linkcount++;

            return getClusterLink(linkcodes, $scope.returnString);
        });
    } else {
        return $q.resolve();
    }
}

Upvotes: 1

bvakiti
bvakiti

Reputation: 3611

promise has to be returned by the function before resolve or rejecting it.

function getClusterLink(linkcodes, returnString) {
var deferred = $q.defer();
$scope.returnString = returnString;
if (linkcount < linkcodes.length) {
    contractorService.gethyperlink(linkcodes[linkcount])
    .success(function (data) {
        var vchUrl = data[0].vchUrl;
        var end = vchUrl.length;
        var docID = vchUrl.substring(vchUrl.indexOf("=") + 1, end);
        var vchLinkName = data[0].vchLinkName;
        var yay = '<a href="" ng-click="getDocumentByID(' + docID + ')">' + vchLinkName + '</a>';
        var yCode = "|Y" + linkcodes[linkcount] + "~";
        $scope.returnString = $scope.returnString.replaceAll(yCode, yay);
        linkcount++;


    })
 return getClusterLink(linkcodes, $scope.returnString);
}
else {
    deferred.resolve();
}
return deferred.promise;
};

.then is implemented on promise object. So as the function is returning the promise ,.then would work fine.

You can look at this sample https://jsbin.com/daseyu/edit?html,js,console,output It works fine.

I think the problem is because you are returning getClusterLink in success. You can return in end of if loop and not in .success.

Hope this helps.

Upvotes: 1

Related Questions