Cancel Previous Ajax Request and Start New One in Angularjs - 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);

Related

AngularJS get value from API only if not already set

I have service to get some data from API and serve them to application.
Simple function like this:
getEnvironmentStatus() {
var _this = this;
var req = {
method: "GET",
url: "/api/system/hosting",
headers: {},
data: {}
}
return _this.$http(req);
}
In some other place I have:
determineHostingEnv() {
var _this = this;
this.$env.getEnvironmentStatus()
.then(function(response){
_this.EnvHositng = response.data.cloud_hosted;
}, function(error) {
});
}
If I need the same information in other place (other controller), I would need to call api again.
How can I make getEnvironmentStatus() function to call API only once and store data in local variable, so it can serve that variable next time it is asked for it, instead of calling API?
Also, what if that value will get requested a few times before the first API will return value? Can I prevent calling that API a few times?
One can cache the promise:
httpPromiseCache = null;
getEnvironmentStatus() {
var _this = this;
var req = {
method: "GET",
url: "/api/system/hosting",
headers: {},
data: {}
}
if (!_this.httpPromiseCache) _this.httpPromiseCache = _this.$http(req);
return _this.httpPromiseCache;
}
The service will only execute the HTTP request once.

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

Angular ng-table loading from server with pagination

I am trying to figure out how to populate an ng-table and apply the total value for the params. It appears there are examples that are showing almost what I'm doing - but not exactly and the total never gets set.
$scope.tableParams = new NgTableParams({page: 1, count: 25},
{
counts: [],
getData: function(params)
if (CompaniesView.ViewInitialized)
return CompaniesView.RetrieveCompanies($scope, $http, function ()
{
params.total($scope.RequestFilter.TotalCompanies);
return $scope.TableParams.data;
});
}
});
My RetrieveCompanies function retrieves he data - and will call a callback function on completion. I was under the impression at this point I could set the params.total, but is not working. I see that examples are doing similar, except they are performing a jQuery API operation directly. I am not sure why this does not work. I would have thought anytime setting the total would cause the table pagination controls to update - but it appears it has to be done within the detData call. But if you are making an async call how can we have the total set in the call since it won't have data until the async completes - which means the
getData call has already finished.
Probably missing some concept here -- but I am not an expert when it comes to jQuery or angular.
Peter
Update:
RetrieveCompanies function
RetrieveCompanies: function (scope, http,callback)
{
scope.IsLoading = true;
var Data =
{
AuthoirzationType: TokenRetrieval.SessionAuth,
SessionId: activeSession
};
var tokenRequest =
{
params: Data
};
performVeilabilityTokenRetrieval(http, tokenRequest,
function (response)
{
if (true)
{
if (!response.HasError)
{
scope.RequestFilter.State = scope.selectedState.Value
scope.RequestFilter.regionsearch = scope.selectedRegion.id;
scope.RequestFilter.checkadminStaff = scope.selectedAdmin.value;
//tableParams
scope.RequestFilter.Page = scope.tableParams.page();
scope.RequestFilter.PageCount = scope.tableParams.count();
var config =
{
headers:
{
Authorization: 'Bearer ' + response.RequestToken
},
params: scope.RequestFilter
}
http.get(CompaniesView.Companies_api_urls.loadCompaniesRequest, config)
.then(
function (response)
{
scope.RequestFilter.TotalCompanies = response.data.companieslistTotal;
scope.TableParams.data = response.data.companies;
if (callback != null) callback();
},
function (data, status, headers, config) //error
{
scope.IsLoading = false;
}
);
}
else
{
scope.request.requestToken = null;
//CreateExpenseView.PrepareRESTResults(data.RestResults);
}
}
else
{
scope.request.requestToken = null;
scope.request.error = data.replace(/\"/g, "");
}
});
}
Ok; finally found what was wrong. The ng-table getData operation requires a promise to be returned. My function was not configured as a deferred promise and once I realized this I put in place the required modification for my data retrieval to return a promise. One big point -- when I wrapped my call with a when - I completed with a done - and getData is operating off a then (from the promise). Once those changes were in place the pagination (total) operation worked.
Peter

Promise Chains in 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
});
}

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