Loading...

angular 2+ canDeactivate async:false


"async: false" has been removed from the chrome browser.

Therefore, I can no longer remove a user from my site when a page is closed. Is there anyway around this, I have tried using an observable but it doesn't seem to call my API and the system closes.

You also can't use:

this.bookOutService.DeletebookOuts().subscribe(()=>{return true;}); 

as this is an Observable<boolean> | boolean.

@HostListener('window:beforeunload')
  canDeactivate(): Observable<boolean> | boolean {

$.ajax({
      type: 'DELETE',
      async: false,
      url: '/api/bookoutAPI/DeleteBookOuts',
    });

    return true;

    //return new Observable<boolean>((observer) => {
    //  debugger;
    //  this.bookOutService.DeletebookOuts().map(() => {
    //    observer.next(true);
    //    observer.complete();
    //  }).take(1);
    //});
  }
- - Source

Answers

answered 1 week ago David Synnott #1

A general problem in programming is what to do when you are waiting for something else to happen. This happens a lot in javascript, be it user input or requesting things from external APIs. Javascript copes with this by having certain things that are asynchronous. There are not many reasons to force something to be synchronous (in other words wait for something to complete before moving on). This is especially true in javascript land as if you are forcing the thread to wait for the completion of an xhr your UI may lock up etc.

I'd suggest that making this function asynchronous would be the best idea.

I'm not sure about the jQuery ajax API but removing async false might be enough. There are some other issues also.

Observables:

RXJS is different to the 'normal' javascript asynchronous pattern of callbacks or promises. With Observables you define a set of actions. Then when you subscribe to it, it preforms those actions. This is an oversimplification. For more details I'd suggest https://www.learnrxjs.io/concepts/rxjs-primer.html and the whole site in general. I much prefer it to the docs themselves. So in you are example you are only defining a set of things to happen, you are not subscribing to the observable therefore nothing actually happens.

HostListener:

HostListener is syntactic sugar for target.addEventListener(eventType, callback). In your case target is window, eventType is 'beforeunload', and callback is something that calls '/api/bookoutAPI/DeleteBookOuts' on your API. What it does not need is any return value. It can also be as asynchronous as you want it to be. Since HostListeners don't care about the return value I'd suggest you remove the typescript definition of it (i.e. remove everything between canDeactivate() and {. If you prefer to always specify a return type you can use void.

2 possible solutions:

@HostListener('window:beforeunload')
canDeactivate() {
  $.ajax({
    type: 'DELETE',
    url: '/api/bookoutAPI/DeleteBookOuts',
  });
}

Or

@HostListener('window:beforeunload')
canDeactivate() {
  this.bookOutService.DeletebookOuts().pipe(take(1)).subscribe(
    () => console.log('Success'), //Handle Success
    error => console.log(error) //Handle Error
  );
}

Things to note is the removal of the return type from both. In the first async is gone, in the second the is a subscribe() (I also used the newer piped operators, rather than the method chaining).

It's also worth noting that you might not need the take(1) depending on the implementation of DeletebookOuts, I'm assuming it's being used to avoid manually unsubscribing. It's a bit off topic from this thread though see Is it necessary to unsubscribe from observables created by Http methods? for some more info on that, or google rxjs memory leaks.

comments powered by Disqus