$q replacement for .when() and .finally() - angularjs

I am migrating AngularJS to Angular
Trying to replace $q with Promise
I have
$q.when(btn.onClick()).finally(test => {
// code
})
I have replaced it with the below code and not sure if that is the exact replacement.
Promise.resolve(btn.onClick()).then(test => {
// code
})
From $q.when() I see we can use .resolve() for .when()
but what is the replacement for .finally()

Start by binding a component template button click to your template logic
<button (click)="onClick()">Click</button>
onClick() {}
Then you can use Promise.all for several promises, or .then for a single promise.
Although, if I may suggest, while migrating, you should consider using Observables, as they're way more powerful than promises and natively integrated with Angular.
Here is one of my previous answers to get started rapidly with Observables.

Since you mention you're migrating, using observables is preferred when possible to using promises. From the documentation:
You can often use observables instead of promises to deliver values asynchronously. Similarly, observables can take the place of event handlers. Finally, because observables deliver multiple values, you can use them where you might otherwise build and operate on arrays.
https://angular.io/guide/comparing-observables
That being said, finally is a part of the promise API and can be found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally

//realised that's not the question. my bad!
You could use
.then(function(){
})
as many times as you want, theres no true replacement for finally() in my knowledge

Related

How to call two functions after angularjs after service success

In angular JS 1.6 how to call the two functions simultaneously after we get the success response from service. Is it possible ?
Wrap both function within .success():
this.myPromise().success((response) => {
this.myFunctionOne(response);
this.myFunctionTwo(response);
})
This way, .success() will fire two functions.
But actually, I have no idea if this is what you were asking for..

Angular JS $timeout vs $interval

What's the difference? When should I use which? I am new to Angular & they look very similar to me. I would rather follow best practices from the start.
$interval executes a callback repeatedly, while $timeout simply delays the execution of a callback (doesn't repeat). So, no, they're not the same. Additionally, it should be noted that both of them are wrappers for window.setInterval and window.setTimeout respectively.
I would also like to recommend to read this great article written by John Resig on how Javascript timers work.
Here's some info extracted from djvirgen's response to a similar Reddit question:
You should always be using $timeout in Angular apps. Here's why:
It's injectable, making testing easier with ngMock.
It runs a digest to ensure your view is updated.
It is thenable (it's also a promise).
However, if you don't want a digest to run, you can simply pass false as the third argument.
I would guess $interval has similar advantages.

AngularJS - binding/watching a function which returns a promise

I posted an issue on the AngularJS github but it doesn't seem to be getting a whole lot of attention and I wasn't able to fix it myself since it's a pretty low-level issue, so I think it's time to look for a workaround.
Angular allows you to put a promise (or anything with a .then(...) function) into your scope, and once it is resolved, all $watches and anything bound to that promise will use the resolved value. The issue arises when you use a function to return a promise, as the same doesn't apply - it's handled like a plain object.
For example:
var helloDef = $.Deferred();
$scope.hello = helloDef.promise();
$scope.getHello = function() {
return $scope.hello;
};
$timeout(function() {
helloDef.resolve('Hello!');
}, 1000);
Fiddle
Here using ng-bind="hello" works fine and outputs Hello!, but ng-bind="getHello()" outputs [object Object] as the internal $watch returns the promise object. Works the same way with $q instead of $.Deferred.
In my actual code I'm creating the promise the first time the function is called, so I can't just pre-make the promise and refer to that in scope.
I also need it for more than just ng-bind, so making my own binding directive which handles this case properly isn't viable.
Anyone have any ideas? I'm currently returning the promise if the data hasn't resolved and the actual result if it has, but that's a pain to work with. Anything bound to the data briefly causes weird side effects as the data is being loaded, like ngRepeat using the promise object instead of the resolved value to create elements.
Thanks.
UPDATE: Pull request: https://github.com/angular/angular.js/pull/3605
UPDATE 2: For future reference, automatic promise unwrapping has been deprecated in the 1.2 brach.
For some things, I use $resource. If I need to wait for it, $then works well:
var r = $resource...get...
var p = r.$then...
Otherwise, I build my own resource-like object that is not a promise, but has a promise that I can wait for.
Pull request merged, it should be fixed in 1.2.0 so I'll mark this as the answer.

How to Check Whether an Angular $q promise Is Resolved

I understand that typically one would just attach continuation code with a then() call and chain behaviour when using promises.
However, I want to kick off a promise-wrapped asynchronous call and then separately kick off a 3-second $timeout() so I can take a UI action, ONLY IF the original promise has not yet completed. (I anticipate that this would only happen on slow connections, mobile devices on 3G, etc.)
Given a promise, can I check whether it's complete or not without blocking or waiting?
I guess this was added in a recent version of Angular but there seems to be now an $$state object on the promise:
var deferred = $q.defer();
console.log(deferred.promise.$$state.status); // 0
deferred.resolve();
console.log(deferred.promise.$$state.status); //1
As noted in the comments this is not recommended as it might break when upgrading your Angular version.
I think your best option as is, (without modifying the Angular source and submitting a pull request) is to keep a local flag for if the promise has been resolved. Reset it every time you setup the promise you're interested in and mark it as complete in the then() for the original promise. In the $timeout then() check the flag to know if the original promise has resolved yet or not.
Something like this:
var promiseCompleted = false;
promise.then(function(){promiseCompleted=true;})
$timeout(...).then(function(){if(!promiseCompleted)doStuff()})
Kris Kowal's implementation includes other methods for checking the state of the promise but it appears Angular's implementation of $q unfortunately doesn't include these.
It doesn't seem to be possible, as #shaunhusain already mentioned. But maybe it's not necessary:
// shows stuff from 3s ahead to promise completetion,
// or does and undoes it in one step if promise completes before
$q.all(promise, $timeout(doStuff, 3000)).then(undoStuff);
or maybe better:
var tooSlow = $timeout(doStuff, 3000);
promise.always(tooSlow.cancel);
I have had a similar problem where I need to check if a promise has returned. Because AngularJS's $watch function will register a change while rendering the page even if both new and old values are undefined, I have to check to see if there is any data worth storing in my external model.
It is definitely a hack but I do this:
$scope.$watch('userSelection', function() {
if(promiseObject.hasOwnProperty("$$v"){
userExportableState.selection = $scope.userSelection;
}
};
I know that $$v is an internal variable used by AngularJS, but it has been quite reliable as an indicator of a resolved promise for us. Who knows what will happen when we upgrade to AngularJS 1.2 :-/ I don't see any mention of improvements to $q in the 1.2 docs but perhaps someone will write a replacement service with a better feature set closer to Q.
I don't know your exact scenario but it is more typical to put a timeout in place immediately after making the asynchronous call (and generating the promise).
Providing the setTimeout() statement is in the same event thread as the asynchronous call, you needn't worry about the possibility of a race effect. As javascript is strictly single threaded, the promise's .then() callbacks are guaranteed to fire in a later event thread.

How to get value of promise that already resolved?

I have a promise that I am binding to in my UI. When the promise resolves and the UI element renders I can then click on that UI element. In my controller code where I handle the click I would like to act on the value of the promise. At this point in my angular code I already know that the promise is resolved.. but when I want to get the value its still a promise.
Whats the best way to get the value of the promise... given that I know it must have resolved?
Promises are always promises - and that's how they should be. While it is possible to bind a promise directly to the view, I generally discourage this practice because it lacks transparency and can lead to view flickering. A better solution is to assign a scope value in a then call:
myService.then(function( val ) {
$scope.val = val;
});
When $scope.val is ready, it can always be treated directly as a value - because it is.
That said, if you want to do the promise assignment directly, you just have to treat it like a promise; that is, you need to call promise.then(function () { ... });. This seems like an inconvenience, but it's actually a testament to just how powerful promises are.
If you want some more info on promises, I pontificated on them (and provided code examples) for a recent Google+ Hangout, where I covered the advantages, common uses, and best practices of promises in AngularJS: AngularJS Hangout -- Promises, Promises
Promises, Promises. The idea of never-ending promise chains was specifically addressed, though I don't have a timecode off the top of my head.
Hope this helps!
What's tricky to understand is that you might think that if the Promise is not yet full-filled then maybe if I wait a bit I can test again to see if by now it has a value. But that is not possible because as explained on MDN:
"Callbacks will never be called before the completion of the current run of the JavaScript event loop."
So as long as your currently started function is running, the Promise can not be full-filled. It has no "value" during the current run of the event loop. "Promise" means "I promise to maybe give it to you during the NEXT event-loop run".
You could save that promise to a global variable and then when a user clicks on a button in the browser a new event-loop starts by running your event-handler which can put another "when()" onto the promise such that if the promise is resolved by that time the new when-function takes the value it gets as argument and saves it into a variable from which you can read it. No need to write it to console, to see that it is there.
That for me was the tricky part, I thought yes sure I can make the Promise write to the console, but I can't read from console, so how can I get that value into the rest of my program? Answer: Wait till the current event-loop is over, then you can.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

Resources