Always do action before and after $http - angularjs

I want my app to always do some actions before and after $http running like loading animation or delete all messages.
// Add loading animation + Remove all messages
$http({}).then(function(response) {
// Remove loading animation + Add Success messages
}, function(response) {
// Remove loading animation + Add Failure mesages
});
But if I code like this, my code is not DRY.
How can I do this without repeat myself?
Thank you!

You should be able to implement it with Interceptors. Read the below one.
http://www.webdeveasy.com/interceptors-in-angularjs-and-useful-examples/
You can inject your custom service into the Interceptor component. In the request function enable animation ON and turn it OFF in the response function. Your home page should also use the same service to have an animated DIV with an ng-if like
<div ng-if="vm.myHttpStateService.isBusy">
..... animation here ...
</div>

Use the promise's .finally method
//Add loading animation + Remove all messages
$http({}).finally(function() {
//Remove loading animation
}).then(function onSuccess(response){
//Add Success messages
}).catch(function onReject(response){
//Add Failure mesages
});
From the Docs:
The Promise API
Methods
finally(callback, notifyCallback) – allows you to observe either the fulfillment or rejection of a promise, but to do so without modifying the final value. This is useful to release resources or do some clean-up that needs to be done whether the promise was rejected or resolved. See the full specification for more information.
-- AngularJS $q Service API Reference -- The Promise API

Related

abort ui-router transition asynchronously without generating a TransitionRejection log

I try to abort a ui-router transition without having an error log entry, i cannot use transition.abort() because i have to wait for a user input ("unsaved changes. continue?") so i return a promise.
$transitions.onExit({exiting: 'main.settings'}, function(transition) {
var deferred = $q.defer();
// promise testing
$timeout(function(){
// here i need to create a Rejection Object with type = RejectType.ABORTED
deferred.reject(false);
}, 500);
return deferred.promise;
});
If i reject the promise, i get the error log entry, because i don't know, how to create a Rejection with a RejectType.ABORTED in my controller. How can i get access to the Rejection Class?
Or is there any other way, how i can abort a transition asynchronously without creating a error log entry?
Using Angular 1.5.1 and ui-router 1.0.5.
Also asked at https://github.com/ui-router/core/issues/35.
Thanks
Returning rejected promise or false value in transition hook seems like the most natural way to abort the transition.
However if you don't want to clutter the log with the error messages you need to provide defaultErrorHandler() as described here - https://ui-router.github.io/ng1/docs/latest/classes/state.stateservice.html#defaulterrorhandler
If you would like to process some specific transitions errors you need to
provide onError hook for this as described here - https://ui-router.github.io/ng1/docs/latest/classes/transition.transition-1.html#onerror
I solved this issue by defining my own defaultErrorHandler(). Now i can prevent error messages to show up after aborting a transition.
Thanks # Pavel Bely

Implementing page loader in Angular using promise

I am wondering what would be the best way to implement a function, that would be responsible for toggling a gif on certain requests. I don't want to display it on all of the http requests, so I don't want to place it within the interceptor - I want to create a service.
I was most likely going to go with a function that will work as following:
LoaderFunction(SomeFunction())
Which will toggle a img or whatever whenever the promise is initiated and resolved. The SomeFunction() will usually be http requests, which already have their own promise.
Thanks!
The easiest way would be to use a counting semaphore and the disposer pattern. It would work for any number of ongoing requests.
withLoader.count = 0;
function withLoader(fn){
if(count === 0) initiateLoader();
count++;
return $q.when(fn).finally(function(){
count--;
if(count === 0) finishLoader();
});
}
This binds a scope to the lifetime of an event - like RAII in C++. This'd let you do:
withLoader(someFunction);
withLoader(someFunction);
withLoader(function(){
return $http.post(...);
}).then(function(){
// http request finished, like your normal `then` callback
});
The loader would finish when the counter reaches 0, that is when all requests finish.
Since it's Angular, you probably want to put withLoader in its own service and have a directive manage the loading itself.
Well, the easiest way to do it is through the use of promises on the $http calls themselves.
Example:
$http.post("/", data, function() {
initiateLoader(); // this is a function that starts the loading animation.
}).success(function (data) {
finishLoader(); // this is a function that ends the loading animation.
}).catch(function(err) {
finishLoader(); //so the loader also finishes on errors.
});

Angularjs - Can i use a controller to track when all http requests it makes are completed

I have web page interface that has three main blocks. Each block has controllers that make http requests. I want to track the calls for each block so i can unblock the interface for each block when all its calls are completed. I have a $http.interceptor that keeps count of ALL http requests and responses for the page, and can block the page until all requests have been completed, but the client doesnt like this approach.
Any suggestions.
Thanks ahead of time.
Yes, just inject and use angular's $q service and $q.all(promises), which according to the documentation
combines multiple promises into a single promise that is resolved when all of the input promises are resolved.
You can use code that looks something like this
var promiseA = $http.(......);
var promiseB = $http.(......);
var promiseC = $http.(......);
$q.all([promiseA, promiseB, promiseC]).then(function() {
//do whatever and unblock
});
one very simple way to do achieve this would be to set a "block" model on each of those individual controllers until the success of your http request. That eliminates the need for any additional controllers. Example code for inside of one of those controllers:
js
$scope.block1Loading = true;
$http
.get(url)
.success(function() {
$scope.block1Loading = false;
});
html
<div ng-controller="Block1Controller"
ng-class="{'blocked': block1Loading}">block 1</div>

Testing an event while an ajax call is in progress using Protractor + Angular

I am using protractor 1.7.0 and angular 1.2.
I have a functionality that when i click a button say 'Load Results' an ajax request is fired, meanwhile the results are coming back I see a button say 'Cancel Request' (to cancel the ongoing ajax request, this button gets hidden when ajax response is received).
Now to test it in protractor I am wirting something like this
//to load the results
element(by.css('#load-results')).click();
//to cancel ongoing ajax request to load results
element(by.css('.search-cancelled')).then(function(){
element(by.css('.search-cancelled')).click();
});
it gives me an error saying that element is not visible.
As far as i know protractor waits for angular to resolve its promises before executing the next statement. So till the time it reaches this code
element(by.css('.search-cancelled')).then(function(){
element(by.css('.search-cancelled')).click();
});
the ajax call has returned and thats why the element gets hidden.
Is there a way i can make protractor not wait for the angular promise and execute my code when the ajax request is going on?
Looks like you could do it this way:
$('#load-results').click();
waitElementToBeShown($('.search-cancelled'));
$('.search-cancelled').click();
Here is the code for help function:
var waitElementToBeShown = function (elm) {
browser.wait(function () {
return elm.isPresent();
},15000);
browser.wait(function () {
return elm.isDisplayed();
},15000);
};

handling $http.get and $http.post errors in Angularjs

Folks,
I am using $http.get and $http.post all over my code. I am kind of lost as to how to handle errors that occur during these calls in a global fashion.
Currently I have .success(doSomething).error(doSomething) on every call.
I would like to change this and instead simply display the error on top of my page.
I read about using interceptors with myapp.something. But I absolutely do not understand how to implement this.
Kindly assist
Response interceptors are attached during the config phase of an angularjs app. You can use them to globally respond to any $http request. Be aware, template files also use $http request, so you may wish to filter some requests in your interceptor to only the ones you wish to respond to.
A good understanding of the promises pattern is needed to successfully use response interceptors.
Heres an example of how they are used:
angular.module('services')
.config(function($httpProvider){
//Here we're adding our interceptor.
$httpProvider.responseInterceptors.push('globalInterceptor');
})
//Here we define our interceptor
.factory('globalInterceptor', function($q){
//When the interceptor runs, it is passed a promise object
return function(promise){
//In an interceptor, we return another promise created by the .then function.
return promise.then(function(response){
//Do your code here if the response was successful
//Always be sure to return a response for your application code to react to as well
return response;
}, function(response){
//Do your error handling code here if the response was unsuccessful
//Be sure to return a reject if you cannot recover from the error somehow.
//This way, the consumer of the $http request will know its an error as well
return $q.reject(response);
});
}
});

Resources