Promise Chains in angularjs - angularjs

I am uploading attachments using rest api in SharePoint 2013,for this I need to call upload attachment method on synchronous.
Because If I call upload attachment method asynchronous I am getting 409 conflict error.
How to chain promise objects in for loop.i.e I want to call second attachment method in first attachment success and so on..
Please help me in best approach of chaining of promises in for loop.
Common method for saving attachments:
var saveFileAngularJS = function (file, url) {
var deferred = $q.defer();
getFileBuffer(file).then(function (fileArrBuffer) {
$http({
method: 'POST',
url: baseUrl + url,
headers: {
'Accept': 'application/json;odata=verbose',
'Content-Type': undefined,
'X-RequestDigest': jQuery("#__REQUESTDIGEST").val()
},
data: new Uint8Array(fileArrBuffer),
transformRequest: []
}).then(function successCallback(data) {
deferred.resolve(data);
alert('Successfully saved.', data);
}, function errorCallback(error) {
deferred.reject(error);
alert('Failed to save!!!.', error);
});
});
return deferred.promise;
};
Method calling :
for (var i = 0; i < $scope.files.length; i++) {
var file = $scope.files[i]._file;
var response = lssDealService.insertAttachment(transactionId, file);
}
var insertAttachment = function (dealId, file) {
var attachmentUrl = listEndPoint + "/GetByTitle('TransactionList')/GetItemById(" + dealId + ")/AttachmentFiles/add(FileName='" + file.name + "')";
return baseService.saveFile(file, attachmentUrl);
};
Insert attachment will call SaveFile method.
I want to run this for loop sequentially, once the loop has been completed I need to process all promises and display success message to user.
Please help me to writing the chaining promises in effective way.

Lets say you have the attachements as an array,
function uploadMyAttachements() {
return myAttachements.reduce(function(promise, attachment) {
return promise.then(function () {
return upload(attachment);
})
.then(function(result) {
console.log('RESULT FOR LAST UPLOAD', result);
});
}, Promise.resolve());
}
function upload(attachment) {
//upload the attachment to sharepoint
//and return a promise here
}
uploadMyAttachements().catch(function(err) {
//if anything in the promise chain fails
//it stops then and there and CATCHED here
});
Now whats happening here, using the Array.reduce, we create a chain of promises like shown below
upload(0).then(handleResult_0).upload(1).then(handleResult_1)....
and it execute one by one as you expected

Throwing my 2 pennies:
$scope.attachments = []; //modified via binding.
function uploadAttachments(){
//Reduce the files array into a promise array with the uploadOne method
//then return the promise when every promise has been resolved or one has rejected.
return $q.all($scope.attachments.reduce(uploadOne, []));
}
function uploadOne(file){
//Upload one, return promise. Use $http or $resource.
}
//Note - a more advanced way of doing this would be to send the files as batch (one
//$http post) as FormData. There are some good wrappers for angular.
$scope.upload = function(){
uploadAttachments().then(function(results){
//Array of results
}).catch(function(e){
//Error handler
});
}

Related

Cancelling pendingRequests is not working for angularJS 1.7.2 version

I am trying to cancel pending api calls when the same api's are called again. I have dropdown onChange of which I am making my api call, here api call taking a lot of time to return data so i am cancelling all previous calls which are in pendingRequest array and keeping only the latest triggered call. please go through my code below
in my controller
angular.forEach($http.pendingRequests,function(r){
console.log(r.contractId);
if (r.contractId && r.contractId !== selectedContract) {
r.cancel.resolve('cancelled');
}
});
Here I am checking if the pending request is latest or not, by comparing current selected contract with pendingRequest array.
This is how I have written my service
getDashboardData:function(selectedContract) {
var deferred = $q.defer();
var cancel = $q.defer();
$rootScope.loaderOn=true;
var url = 'my_url_here';
$http.get(url, {
ignoreLoadingBar: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
cancel:cancel, //this is of type $q.defer();
contractId:selectedContract // here i assigned contrract id just to delete all pending api's other than current
}).then(function(data){
deferred.resolve(data.data);
$rootScope.loaderOn=false;
},function(error){
console.log(error);
return deferred.reject(err);
});
return deferred.promise;
}
I want to cancel or reject pending api calls. Any help will be appreciated thank you. Let me know if any other info required. Please correct me here.
I referred $http and doubt if cancel property exist in config object of $http.get function. You can use timeout property and use the value for cancelling the existing request.
I have replaced cancel property with timeout.
I hope below code helps.
// Declare the below objects in service level not inside getDashboardData function
var deferredObj = '';
var existingRequest = '';
getDashboardData: function(selectedContract) {
var deferred = $q.defer();
// Below condition will check to cancel the existing request
if (existingRequest) {
existingRequest = '';
deferredObj.resolve();
deferredObj = '';
} else {
deferredObj = $q.defer();
}
$rootScope.loaderOn=true;
var url = 'my_url_here';
existingRequest = $http.get(url, {
ignoreLoadingBar: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
**timeout : deferredObj.promise**, //this is of type $q.defer();
contractId:selectedContract // here i assigned contrract id just to delete all pending api's other than current
}).then(function(data){
deferred.resolve(data.data);
$rootScope.loaderOn=false;
},function(error){
console.log(error);
return deferred.reject(err);
});
return deferred.promise;
}
const request = new Map() // put this outside the main function
getDashboardData() { // call this on change
const url = 'my_url_here'; // value should be constant
const oldRequest = request.get(url) // get the last promise request
oldRequest.reject && oldRequest.reject('old request') // cancel's the last promise request
// last promise request successCallback won't be called since the promise is already rejected
$q((resolve, reject) => { // creates a new promise
request.set(url, { resolve, reject }) // store resolve, reject
return $http.get(url) // create api request
})
.then(successCallback) // on request success
.catch(rejectedOrErrorCallaback)
}
you can re implement it to something like this.
btw as per documentation. $http.pendingRequests is primarily meant to be used for debugging purposes. so i think that's a flag to stay away from using

How return the promise of $http in angularJs

I am new to AngularJS. How can I return the response of "response.data" as a typical function?
Because $http generates a promise, when the function finishes it doesn't return the server response.
In my controller I have:
this.message2 = function() {
$http({
url : 'dataset_of_model',
method : "POST",
data : {
'experiment' : 'rcp85',
'model' : 'HadGEM2-ES',
'frequency' : 'day'
}
}).then(function(response) {
console.log('qui');
console.log(response.data);
return response.data;
}, function(response) {
//fail case
console.log(response);
console.log(fallito);
return response;
});
};
If I do:
this.message2 = function() {
var = temp;
$http({
url : 'dataset_of_model',
method : 'POST',
data : {
'experiment' : 'rcp85',
'model' : 'HadGEM2-ES',
'frequency' : 'day'
}
}).then(function(response) {
console.log('qui');
console.log(response.data);
temp = response.data;
}, function(response) {
//fail case
console.log(response);
console.log(fallito);
return response;
});
return temp;
};
The return temp doesn't have the data because it returns before data, even if I wait for example 10 seconds before return.
How can I return data in a synchronous way?
Thanks!!
Try this.
this.getResults = function(){
return $http.get(url).then(function(res){
//Resquest successs
}, function(err){
//Resquest fail
});
}
And then
MyFooService.getResults().then(...);
I'm not sure why would would want to do that? You're returning response.data anyways in the first option. You should also probably add return before the $http (that way you're returning the promise). However, anything that you want to happen synchronized with the response must be in the .then block. For example, if you wanted to get a response of all goals scored, then add that number to some variable, you'd have to put that functionality in the .then block, then return the response.data at the end of the block.
That way, the functions executed inside the then block are synchronous.
You have no guarantee over the functions executed outside the then block, unless you want to hack it with $timeout (stop for 2 secs, then execute that return temp), which I don't recommend.

Angular promise callback not firing

I have this app that uploads a file to a server using $cordovaFileTransfer and then sends data about the file to the same server. The file is transferred fine. The data is then sent to the server, and the server responds. But the response does not make it back to the promise callback. Why?
$scope.sendPost = function(data) {
//first upload a file then send more data about the file
$cordovaFileTransfer.upload('http://example.com', 'myfile.txt', options)
.then(function(result) {
var promise = MyFactory.sendFileData(data);
});
promise.then(function(response) {
//we never make it to here
});
}
and in MyFactory:
service.sendFileData = function(data) {
return $http({
//bunch of parameters. This function works, data is sent to the server and a response received
}).then(function(response) {
//this is fired when the response is received from the server. All is good so far.
return.response.data
});
}
return service;
$cordovaFileTransfer.upload returns a promise object, which you could use to build up promise chaining mechanism.
Code
$scope.sendPost = function(data) {
//get hold on `upload` function promise
var promise = $cordovaFileTransfer.upload('http://example.com', 'myfile.txt', options)
.then(function(result)) {
//return MyFactory.sendFileData promise here which will follow promise chaining
return MyFactory.sendFileData(data);
});
//promise.then will get call once `MyFactory.sendFileData` complete it
promise.then(function(response) {
//will get called once `sendFileData` complete its promise
});
}
its because you're relaying on another promise's callback to initiate a the promise and.. most probably before the promise gets initialized you are attaching a callback tot it.. so at the time of you attaching the callback, the promise is not yet initialized i.e. promise is null.. so in your console you'll see an error..
try doing some thing like
var x = function(response) {
//we'll make it to here now...
}
$cordovaFileTransfer.upload('http://example.com', 'myfile.txt', options)
.then(function(result)) {
var promise = MyFactory.sendFileData(data);
promise.then(x);
});
You should follow #PankajParkar solution though it's a better approach...
$scope.sendPost = function(data) {
//first upload a file then send more data about the file
$cordovaFileTransfer.upload('http://example.com', 'myfile.txt', options)
.then(function(result)) {
return MyFactory.sendFileData(result.data);
})
.then(function(response) {
});

Cancel Previous Ajax Request and Start New One in Angularjs

following solution is not working for me some how
How to cancel an $http request in AngularJS?
above solution effect - abort new ajax call also,it should be allow new ajax call and abort old ajax call
my code
$scope.callajax = function () {
var canceller = $q.defer();
var data = {};
data['id'] = id;
$http({
method: "post",
url: url,
data: $.param(data),
timeout: canceller.promise,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function (response) {
});
canceller.resolve();
};
i am calling this function,if i call this function two time at a time then it should be abort first ajax call and fire new ajax call
The problem with your code is that the canceller.resolve() gets called and cancels the $http immediately. The following works by flagging if an ajax call is active and cancelling the call.
JSFiddle
var canceller,
isSending = false;
$scope.callajax = function () {
console.log("callajax");
if(isSending) {
canceller.resolve()
}
isSending = true;
canceller = $q.defer();
var data = {
html: "<p>Text echoed back to request</p>",
delay: 5
}
$http({
method: "post",
url: "/echo/html",
data: data,
timeout: canceller.promise
}).success(function (response) {
isSending = false;
console.log("success");
}).error(function(data, status) {
isSending = false;
console.log("error");
});;
};
Since, you have the cancelar object inside the function and also calling it, the callajax function will call and then cancel it everytime. To achieve what you want you should be trying something like this -
$scope.cancelHandles = [];
$scope.currentIndex=0;
$scope.callajax = function () {
var cancelar = $q.defer();
$scope.cancelHandles.push(cancelar);
//rest of your code goes here except the last line cancelar.resolve();
$scope.currentIndex = cancelHandles.length;
}
$scope.cancelAjaxCall = function(index) {
cancelHandles[index].resolve();
}
The function call - callajax shall be returning the index in the array of cancel handlers which will map to the number of time you have called the ajax function.
There is a separate function called cancelAjaxCall which will accept an index i.e. the nth number of ajax call which you want to cancel.
If you want to cancel the 3rd call from now in the past simply subtract 3 from the $scope.currentIndex and call the cancelAjaxCall function i.e. cancelAjaxCall($scope.currentIndex-3);

To call function repeatedly itself until it satisfies the condition using promise-Angularjs

I want to post images on server continuously and i am doing this by putting it in a loop of images length.I want to call the function again on the success of previous image upload using promises.
Below is the code i am using
$scope.questionimageuploadfun = function(surveyid, questionid, type, questions) {
angular.forEach(questions, function(value, key) {
$scope.upload = $upload.upload({
url: 'questions/' + questionid + '/options/' + value.id,
file: value.file,
fileFormDataName: 'myfile',
}).progress(function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
}).success(function(data, status, headers, config) {
// file is uploaded successfully
if (!data.error && type == "new") {
toaster.pop('success', "Question", "Question added succesfully");
}
})
// });
}
I searched for the way to use promises but no success.I want to do this on success of every call till the condition gets satisfies
To create a controlled infinite loop with promises can be a bit tricky.
I structured a basic function here for you, but you need to modify it to work to your
$scope.questionImageUploadFun = function(surveyid,questionid,type,questions){
var defer = $q.defer(); // the deferred object, a promise of work to be done
$http.get('someUrl', parameters).then(function(response){
// do something with success response
defer.resolve(response);
}, function(reasonForFail){
// do something with failure response
defer.reject(reasonForFail);
});
return defer.promise; // return the promise
};
// define success function
var onSuccess = function(response){
// declare local parameters here
// call function again
$scope.questionImageUploadFun().then(onSuccess); // success function should call itself again on the next success
};
var onFailure = function(reason){
// do something else?
};
var surveyId = 1;
var questionId = 1;
var type = 1;
var question = 1;
// call the function, since it returns a promise, you can tag a then() on the end of it, and run the success function.
$scope.questionImageUploadFun(surveyid,questionid,type,questions).then(onSuccess);

Resources