How to always run some code when a promise is fulfilled in Angular.js
Solution 1
The feature has been implemented in this pull request and is now part of AngularJS. It was initially called "always" and then later renamed to finally
, so the code should be as follow:
LoadingOverlay.start();
Auth.initialize().then(function() {
// Success handler
}, function() {
// Error handler
}).finally(function() {
// Always execute this on both error and success
});
Note that since finally
is a reserved keyword, it might be necessary to make it a string so that it doesn't break on certain browsers (such as IE and Android Browser):
$http.get('/foo')['finally'](doSomething);
Solution 2
I'm using Umbraco version 7.3.5 back end with AngularJS version 1.1.5 and found this thread. When I implemented the approved answer I got the error:
xxx(...).then(...).finally is not a function
What did work however was always
. If anyone else using an old version of AngularJS finds this thread and can't use finally
use this code instead
LoadingOverlay.start();
Auth.initialize().then(function() {
// Success handler
}, function() {
// Error handler
}).always(function() {
// Always execute this on both error and success
});
Solution 3
For those not using angularJS, and if you're ok with catching the error (not sure if .finally() would do that), you could use .catch().then() to avoid the duplicated code.
Promise.resolve()
.catch(() => {})
.then(() => console.log('finally'));
The catch() might end up being useful anyway for logging or other cleanup. https://jsfiddle.net/pointzerotwo/k4rb41a7/
Solution 4
I would use ngView to render the content of the page and trigger the removal of you modal on the event $viewContentLoaded. See http://docs.angularjs.org/api/ng.directive:ngView for that event and http://docs.angularjs.org/api/ng.$rootScope.Scope for the $on event listener.
Related videos on Youtube
laurent
Updated on July 05, 2022Comments
-
laurent almost 2 years
In my Angular.js application, I'm running some asynchronous operation. Before it starts I cover the application with a modal div, then once the operation is complete, I need to remove the div, whether the operation was successful or not.
Currently I have this:
LoadingOverlay.start(); Auth.initialize().then(function() { LoadingOverlay.stop(); }, function() { LoadingOverlay.stop(); // Code needs to be duplicated here })
It works well, however I would prefer to have something cleaner like this pseudo-code:
LoadingOverlay.start(); Auth.initialize().finally(function() { // *pseudo-code* - some function that is always executed on both failure and success. LoadingOverlay.stop(); })
I assume it's quite a common problem, so I was thinking it could be done but cannot find anything in the doc. Any idea if it can be done?
-
Beetroot-Beetroot about 11 yearsIf you can chain one
then()
, then you can surely chain another ....initialize().then(...).then(...)
. There's no "finally" as such; the final handler is the last one specified. -
laurent about 11 years@Beetroot-Beetroot, that won't work because if
initialize()
fails, you still need to declare both a "success" function and a "fail" function and duplicate code in there. -
Beetroot-Beetroot about 11 yearsWon't work, or just inelegant?
-
laurent about 11 years@Beetroot-Beetroot, I mean it really won't work. I have updated my example to clarify what I mean. As you can see in example 1, the code needs to be duplicated, which is not just inelegant but also harder to maintain. In example 2 (pseudo-code), the function will be executed no matter what, which avoids duplicate code. Here just chaining
then()
functions won't help since I'd still need to handle both failure and success (even though I don't care if it succeeded or not). Perhaps what I'm trying to do cannot currently be done though. -
Beetroot-Beetroot about 11 yearsLaurent, what you want isn't currently available in Angular's lightweight $q service, which provides promises with just one method,
.then()
- see "The Promise API" here. The only freedom is to have one.then()
or to chain multiple.then()
s. You are not the first to wish for a more extensive promise API - the feature you want is formally requested here. -
OZ_ almost 11 yearsFeature request github.com/angular/angular.js/issues/2761
-
laurent almost 11 years@OZ_, I should have mentioned it but I actually ended up implementing the feature in this pull request - github.com/angular/angular.js/pull/2424 It's been accepted and I guess should be part of the main Angular.js release soon.
-
OZ_ almost 11 yearsThank you, @Laurent. It's implemented in 1.1.5 which is on google CDN today :) I think it will not be worse if $http will have same functional "out of the box" :) At this moment I'm trying to figure out and learn how can I wrap $http with $q to get flow, described in your question.
-
laurent almost 11 years@OZ_, I didn't check but I would assume
$http
makes use of the built-in promise service, doesn't it? -
OZ_ almost 11 years@Laurent, I thought built-in promise and $q - different things. But if not.. Will check right now.
-
OZ_ almost 11 yearsIT WORKS!!! Thank you VERY much!
-
Aleyna over 10 yearsApparently
always(callback)
is not implemented or rolled back in angular 1.2.6. We have to usefinally
now. I wonder why the reserved wordfinally
is better thanalways
. -
laurent over 10 years@Aleyna, interesting, when I've implemented the feature, the consensus was to use
always
since that's what jQuery is using and becausefinally
is a reserved JS keyword. Eventually, it seems they went forfinally
anyway with the caveatBecause 'finally' is a reserved word in JavaScript and reserved keywords are not supported as property names by ES3, you'll need to invoke the method like 'promise['finally'](callback)' to make your code IE8 compatible
. Why not, but it seems a bit more trouble than needed. -
laurent over 10 yearsAnd actually Android Browser will also throw an error if using
finally
without quotes. -
Aleyna over 10 years@Laurent, I have checked out the discussion on your pull request. I would second
always
as well. Perhaps maintainers wished to stick with Q's original api.
-
-
Austin Thompson almost 10 yearsFor anyone finding this from a web search, the link in the answer referred to the function
always
but it was changed tofinally
as you can see in this commit (or in the source): github.com/angular/angular.js/commit/… -
laurent almost 10 years@AustinThompson, thanks for the information, I have updated the post.
-
jan over 9 years@this.lau_ does the finally() have to be the last call in the chain, or can I chain more then()s off of it?
-
JacobF over 9 yearsYou sir, made my day!
-
drzaus over 8 years@Brian
finally
returns a promise just like the rest, so you can chain it. However (at least on some versions of Angular) the convenience overloadssuccess
anderror
are only added to the immediate return of$http
, so if you start withfinally
you'll lose those methods. -
greenoldman almost 8 years