I have a problem with angular spinner here, i have a update button inthat i'm using spin and loading needs to be stopped after saving the data in to database without using any timeout function i need stop that loading
function assignLectureToSubject(subject) {
subject.$update();
}
above code is the function for update button
Use a flag. lets call it isUpdating
$scope.isUpdating = false;
function update(){
$scope.isUpdating = true;
$http({
method: 'POST',
url: '/someUrl'
}).then(function successCallback(response) {
$scope.isUpdating = false;
}, function errorCallback(response) {
$scope.isUpdating = false;
});
}
And in the HTML,
<your-spinner ng-show='isUpdating'>
Initially, spinner is hidden. When update is called, the spinner starts showing on the page. And when the event completes, the callback sets the flag to false, thereby hiding it again.
You can implement a genric solution, You can use interceptors, Here is an example. Perform your operation for ShowWaitIndicator and HideWaitIndicator functions
app.factory('waitingInterceptor', ['$q', '$rootScope',
function ($q, $rootScope) {
return {
request: function (config) {
ShowWaitIndicator();
return config || $q.when(config);
},
requestError: function(request){
HideWaitIndicator();
return $q.reject(request);
},
response: function (response) {
HideWaitIndicator();
return response || $q.when(response);
},
responseError: function (response) {
HideWaitIndicator();
return $q.reject(response);
}
};
}]);
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('waitingInterceptor');
}]);
Related
I have 2 functions bindclub() and displayevent(). I want to assure bindclub() to run first always.I have also tried to put both the functions in ng-init but it also does not assured to run bindclub() first
angular.module('app', []).controller("EventCtrl",EventController);
EventController.$inject = ["$scope", "$http", "$window"];
function EventController($scope, $http, $window) {
$scope.bindclub = function () {
$http({
url: '/Master/bindclub',
method: 'post',
}).then(function (response) {
debugger
$scope.clubidname = response.data;
}, function () { alert("Error in binding club"); });
}
$scope.displayevent = function () {
$http({
url: '/Master/displayevent',
method: 'post',
}).then(function (response) {
alert('Displayed');
}, function () { alert('Error in display event'); });
}
$scope.bindclub ();
$scope.displayevent ();
}
Is the second event dependent on the first event? If yes then you may set it as a callback event of the first event, to ensure that it is triggered on the success of the first event.
use callback function wait until bindclub function executing and then start displayevent function
angular.module('app', []).controller("EventCtrl", EventController);
EventController.$inject = ["$scope", "$http", "$window"];
function EventController($scope, $http, $window) {
$scope.bindclub = function(callback) {
$http({
url: '/Master/bindclub',
method: 'post',
}).then(function(response) {
debugger
$scope.clubidname = response.data;
callback() // callback function
}, function() {
alert("Error in binding club");
callback()// callback function
});
}
$scope.displayevent = function() {
$http({
url: '/Master/displayevent',
method: 'post',
}).then(function(response) {
alert('Displayed');
}, function() {
alert('Error in display event');
});
}
$scope.bindclub(function() {
$scope.displayevent(); // this execute after bindclub fucntion
});
}
The function bindclub is indeed being run before displayevent. But these two functions themselves make http calls which have callbacks. There is no guarantee to have the callbacks executed in the order you want.
The only work around I see is to call the other function inside of the callback in bindclub.
The other way is for you to chain the callbacks.
You can attach displayEvent to a custom event that is triggered inside the bindEvent callback.
Check out this SO post for example on how to do this.
Return the promise and then chain them:
$scope.bindclub = function () {
//vvvv RETURN httpPromise
return $http({
url: '/Master/bindclub',
method: 'post',
}).then(function (response) {
debugger
$scope.clubidname = response.data;
}, function () { alert("Error in binding club"); });
}
//CHAIN them
$scope.bindclub()
.then(function () {
$scope.displayevent();
});
Since the $http service returns a promise, the second operation can be chained from the first operation with the .then method of the first promise.
This is http interceptor service that should handle cancellation of previous requests with the same url. I have a problem with handling rejection after calling 'resolve' method which falls into a 'catch' handler of my angular data service.
How to flag this cancellation as intentional, so my data service does not indicate that an error occurred on server side? I don't want to display error message in this case.
(function () {
'use strict';
angular
.module('common')
.factory('abortService', abortService);
abortService.$inject = ['$q', '$filter'];
function abortService($q, $filter) {
var service = {
request: request,
};
var error = "";
var currentRequests = [];
return service;
function request(request) {
if (!request.url.includes('api/')) return request;
var deferred = $q.defer();
request.timeout = deferred.promise;
var existingRequests = $filter('filter')(currentRequests, { url: request.url }, true);
existingRequests.forEach(function (request) {
request.promiseObj.resolve('intentional_reject');//how to flag as intentional reject??
});
currentRequests.push({ url: request.url, promiseObj: deferred });
return request;
}
};})();
And here is my angular data service method:
function getBalanceDueSummary(businessPartnerCode) {
return $http({
method: "get",
url: "/api/BusinessPartnerAPI/GetBalanceDueSummary",
params:
{
businessPartnerCode: businessPartnerCode,
}
})
.then(complete)
.catch(failed);
function complete(response) {
return response.data;
}
function failed(error) { //here my cancellation falls into, but i have no data which indicates intentional cancellation
//logService.exception displays a toastr message when error occurrs
logService.exception(error, 'GetBalanceDueSummary');
return $q.reject(error);
}
}
I have done some digging and found the value 'intentional_reject' in object:
error.Config.timeout.$$state.value
function getBalanceDueSummary(businessPartnerCode) {
return $http({
method: "get",
url: "/api/BusinessPartnerAPI/GetBalanceDueSummary",
params:
{
businessPartnerCode: businessPartnerCode,
}
})
.then(complete)
.catch(failed);
function complete(response) {
return response.data;
}
function failed(error) {
if(!(error.Config.timeout.$$state.value &&
error.Config.timeout.$$state.value=='intentional_reject'))
logService.exception(error, 'GetBalanceDueSummary');
return $q.reject(error);
}
}
I doubt this is the best solution for this but I could not set response status manually...
I'm a bit confused by mixing promises and callbacks
I'm trying to do something like this in a factory
startRecord: function (data) {
return $q(function(resolve, reject) {
myFunction(data,resolve,reject);
})
}
which calls
function myFunction(data,callback,error){
...do stuff
if(worked)
callback(response)
else
error(err)
}
And then call it from within my controller like
factory.startRecord(data).then(function(data)...).catch(function(error)...);
However the then or catch are never called..
Am I going the right way about this?
My problem was the callback was being fired with an empty message before the full message was sent. I had to add some extra checks to stop the callback being fired until the message was ready.
Angular $http call it self return promise, you just need to call it perfectly.
Sample code :
Factory:
angular.module(ApplicationName).factory('calendarFactory', ['$http', function ($http) {
calendarFactory.testCall = function (request_params) {
var req = {
method: 'POST/GET',
url: <URL>,
headers: {
'Content-Type': 'application/json'
},
data: request_params
};
return $http(req);
}
}
Controller :
function testCall(start, end) {
var request_paramas = {
start: start.toString(),
end: end.toString()
};
calendarFactory.testCall(request_paramas).then(
function(success){
//Success method
},function(error){
//Error method
})
}
Here I made a back-end http call from factory itself
I have a service getting items by $http. In the controller I share this data with the view. It works, but when I delete or add new items by $http, I cannot get my list to stay up to date.
I created a refresh() function, that I call every time I add or delete an item, but the refresh applies only from time to time. And not on every action though the function is always duly called and executed.
How should I proceed to get my items refreshed on every action?
Function:
refresh = function() {
itemsService.getItems().then(function(d) {
$scope.items= d;
});
}
Service:
app.factory('itemsService', function($http) {
var itemsService = {
getItems: function() {
return $http.get('items.json')
.then(
function (response) {
return response.data;
}
);
}
};
return itemsService;
});
I have also read about $watch() and tried to make it work in this case, but it does not seem to make any difference:
$scope.$watch('itemsService.getItems()', function(d) {
$scope.items = d;
}, true);
This might be what you are looking for
Angular JS - listen or bind $http request
You can just call your function when the request ends.
You can use an interceptor to do this
var httpinterceptor = function ($q, $location) {
return {
request: function (config) {
//show your loading message
console.log(config);
return config;
},
response: function (result) {
//hide your loading message
console.log('Repos:', result);
return result;
},
responseError: function (rejection) {
//hide your loading message
console.log('Failed with', rejection);
return $q.reject(rejection);
}
}
};
app.config(function ($httpProvider) {
$httpProvider.interceptors.push(httpinterceptor);
});
How can I stop a request in Angularjs interceptor.
Is there any way to do that?
I tried using promises and sending reject instead of resolve !
.factory('connectionInterceptor', ['$q', '$timeout',
function($q, $timeout) {
var connectionInterceptor = {
request: function(config) {
var q = $q.defer();
$timeout(function() {
q.reject();
}, 2000)
return q.promise;
// return config;
}
}
return connectionInterceptor;
}
])
.config(function($httpProvider) {
$httpProvider.interceptors.push('connectionInterceptor');
});
I ended up bypassing angular XHR call with the following angular Interceptor:
function HttpSessionExpiredInterceptor(sessionService) {
return {
request: function(config) {
if (sessionService.hasExpired()) {
/* Avoid any other XHR call. Trick angular into thinking it's a GET request.
* This way the caching mechanism can kick in and bypass the XHR call.
* We return an empty response because, at this point, we do not care about the
* behaviour of the app. */
if (_.startsWith(config.url, '/your-app-base-path/')) {
config.method = 'GET';
config.cache = {
get: function() {
return null;
}
};
}
}
return config;
}
};
}
This way, any request, POST, PUT, ... is transformed as a GET so that the caching mechanism can be
used by angular. At this point, you can use your own caching mechanism, in my case, when session
expires, I do not care anymore about what to return.
The $http service has an options
timeout to do the job.
you can do like:
angular.module('myApp')
.factory('httpInterceptor', ['$q', '$location',function ($q, $location) {
var canceller = $q.defer();
return {
'request': function(config) {
// promise that should abort the request when resolved.
config.timeout = canceller.promise;
return config;
},
'response': function(response) {
return response;
},
'responseError': function(rejection) {
if (rejection.status === 401) {
canceller.resolve('Unauthorized');
$location.url('/user/signin');
}
if (rejection.status === 403) {
canceller.resolve('Forbidden');
$location.url('/');
}
return $q.reject(rejection);
}
};
}
])
//Http Intercpetor to check auth failures for xhr requests
.config(['$httpProvider',function($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
}]);
Not sure if it is possible in general. But you can start a $http request with a "canceler".
Here is an example from this answer:
var canceler = $q.defer();
$http.get('/someUrl', {timeout: canceler.promise}).success(successCallback);
// later...
canceler.resolve(); // Aborts the $http request if it isn't finished.
So if you have control over the way that you start your request, this might be an option.
I just ended up in returning as an empty object
'request': function request(config) {
if(shouldCancelThisRequest){
return {};
}
return config;
}
Here is what works for me, especially for the purposes of stopping the outgoing request, and mocking the data:
app
.factory("connectionInterceptor", [
"$q",
function ($q) {
return {
request: function (config) {
// you can intercept a url here with (config.url == 'https://etc...') or regex or use other conditions
if ("conditions met") {
config.method = "GET";
// this is simulating a cache object, or alternatively, you can use a real cache object and pre-register key-value pairs,
// you can then remove the if block above and rely on the cache (but your cache key has to be the exact url string with parameters)
config.cache = {
get: function (key) {
// because of how angularjs $http works, especially older versions, you need a wrapping array to get the data
// back properly to your methods (if your result data happens to be an array). Otherwise, if the result data is an object
// you can pass back that object here without any return codes, status, or headers.
return [200, mockDataResults, {}, "OK"];
},
};
}
return config;
},
};
},
])
.config(function ($httpProvider) {
$httpProvider.interceptors.push("connectionInterceptor");
});
If you are trying to mock a result like
[42, 122, 466]
you need to send an array with some http params back, its just how the ng sendReq() function is written unfortunately. (see line 1414 of https://github.com/angular/angular.js/blob/e41f018959934bfbf982ba996cd654b1fce88d43/src/ng/http.js#L1414 or snippet below)
// from AngularJS http.js
// serving from cache
if (isArray(cachedResp)) {
resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3], cachedResp[4]);
} else {
resolvePromise(cachedResp, 200, {}, 'OK', 'complete');
}