Rani Radcliff Rani Radcliff - 2 months ago 12
AngularJS Question

Deferred Promises in Function does not Defer Execution of Function

I'm struggling with deferred promises. I have a very ugly string:

me, company name, SSQ ID, the company you are working for (Extraction/XTR/8North) and the tier assigned to your company in question #17.


|Y132~

|Y133~


|Y134~



|Y138~

|Y139~

|Y140~



|Y141~

|Y142~

|Y143~




that I have to replace each occurrence of a "|Y000~" with a URL link. That part of the code is working correctly. The problem is that I can't figure out how to use a promise to wait on the function (which includes deferral of multiple promises) to wait until the function finishes before moving on.

I have this in my "convertString" function:

getAllClusterLinks(indices, returnString)
returnString = $scope.returnString;


Here is the convetString function:

function convertClusterText(questions, field) {
angular.forEach(questions, function (value, key) {
if (value.vchTextBeforeQuestionCluster != null) {
var str = value.vchTextBeforeQuestionCluster;
var returnString = str.replaceAll('|B', '<b>');
returnString = returnString.replaceAll("|b", "</b>");
returnString = returnString.replaceAll("|+", "<br/>");
returnString = returnString.replaceAll("|L", "<");
returnString = returnString.replaceAll("|R", ">");
returnString = returnString.replaceAll("|T", "<table border='1'>");
returnString = returnString.replaceAll("|/T", "</table>");
returnString = returnString.replaceAll("|S", "<tr>");
returnString = returnString.replaceAll("|/S", "</tr>");
returnString = returnString.replaceAll("|C", "<td>");
returnString = returnString.replaceAll("|/C", "</td>");
returnString = returnString.replaceAll("|A", "&#39;");
returnString = returnString.replaceAll("|Q", "&amp;");
returnString = returnString.replaceAll("|P", "&#59;");
returnString = returnString.replaceAll("|W", "&#34;");
returnString = returnString.replaceAll("|H", "<hr style='width: 100%;'>");
returnString = returnString.replaceAll("|U", "<span style='text-decoration:underline'>");
returnString = returnString.replaceAll("|x", "</span>");
returnString = returnString.replaceAll("|N", "<span style='color:black'>");
returnString = returnString.replaceAll("|D", "<span style='color:blue'>");
returnString = returnString.replaceAll("|E", "<span style='color:red'>");
returnString = returnString.replaceAll("|G", "<span style='color:gray'>");
if (returnString.indexOf("|Y") >= 0) {
var indices = [];
var linkCode;

indices = getIndicesOf("|Y", returnString, true);

if (indices.length > 1) {

getAllClusterLinks(indices, returnString)
.then(function () {
returnString = $scope.returnString;

})
value.vchTextBeforeQuestionCluster = returnString;



}
else {
linkCode = getLink(returnString);
contractorService.gethyperlink(linkCode)
.success(function (data) {
var vchUrl = data[0].vchUrl;
var docID = getDocumentID(vchUrl);
var vchLinkName = data[0].vchLinkName;
questions[key].document = docID;
var yay = '<a href="" ng-click="getDocument(cluster)">' + vchLinkName + '</a>';
var yCode = "|Y" + linkCode + "~";
returnString = returnString.replaceAll(yCode, yay);
value.vchTextBeforeQuestionCluster = returnString;
})
}

}
else {
value.vchTextBeforeQuestionCluster = returnString;

}


}
});
};


I need "getAllClusterLinks" to complete before executing the next line. Here is the code for "getAllClusterLinks":

function getAllClusterLinks(indices, returnString) {
var promises = [];
var times = 0
var endIndex = 0;
angular.forEach(indices, function (value, key) {
endIndex = getEndIndicesOf("~", returnString, value);
linkCode = getMultiLinks(returnString, value, endIndex)
var promise = getClusterLinks(linkCode, returnString);
promises.push(promise);
})

return $q.all(promises);
}
function getClusterLinks(linkCode, returnString) {
var deferred = $q.defer();
$scope.returnString = returnString;
contractorService.gethyperlink(linkCode)
.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="getDocument(' + docID + ')">' + vchLinkName + '</a>';
var yCode = "|Y" + linkCode + "~";
$scope.returnString = $scope.returnString.replaceAll(yCode, yay);
})
return deferred.promise;

}


The above code works as expected, but I need it to finish first before setting the line
returnString = $scope.returnString;
.

Tried this but it doesn't work:

getAllClusterLinks(indices, returnString)
.then(function () {
returnString = $scope.returnString;

})


Any assistance is greatly appreciated!

Answer

$q.all(promises) returns a promise. You should be able to use then() .

 getAllClusterLinks(indices, returnString).then(function() {
     returnString = $scope.returnString;
});

[https://docs.angularjs.org/api/ng/service/$q][1]

EDIT: you should resolve your deferred object

sidenote: I believe success() is already deprecated, you should use .then too

function getClusterLinks(linkCode, returnString) {
    var deferred = $q.defer();
    $scope.returnString = returnString;
    contractorService.gethyperlink(linkCode)
    .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="getDocument(' + docID + ')">' + vchLinkName + '</a>';
        var yCode = "|Y" + linkCode + "~";
        $scope.returnString = $scope.returnString.replaceAll(yCode, yay);
        deferred.resolve(); // resolve here
    })
    return deferred.promise;

}