How to block UI until all pending operations are complete?

2k Views Asked by At

I have an Angular 8 web app with NgxSpinner. I'm using it to block UI when some lengthy process is in progress to prevent users from interacting with complex forms while some parts haven't yet fully loaded.

The problem is that NgxSpinner hides itself immediately if some process calls hide, no matter if there is still another process with its own show/hide call pair running. So, the web page is unblocked too early when any shorter process has been completed and has called spinner.hide().

Here's Stackblitz example.

How do I make the NgxSpinner to wait for the last hide to match all show calls?

P.S. It seems an issue with many UI block libraries I've tried - they just don't account for parallel processes calling show/hide multiple times.

3

There are 3 best solutions below

0
On BEST ANSWER

Create one service for spinner and keep show/hide count there.

export class MySpinnerService {
  showIndex = 0;
  hideIndex = 0;

  constructor(private spinner: NgxSpinnerService) {}

  show() {
    this.showIndex++;
    this.spinner.show();
    console.log('show spinner', this.showIndex);
  }

  hide() {
    this.hideIndex++;
    if (this.showIndex === this.hideIndex) {
      this.spinner.hide();
      console.log('hide spinner', this.hideIndex);      
    }
  }

So when showIndex and hideIndex equals you need to hide spinner.

Call in your component

this.mySpinner.show(); // show spinner
this.mySpinner.hide(); // hide spinner

Here is example in Stackblitz.

1
On

you can make a use of Promise. Each Process function will return a promise and then you can make a use of Promise.all function which will be called once all the promise is resolved. you can hide the spinner in promise.all method. Please find below the sample code.

this.spinner.show();
let p1 = new Promise((resolve, reject) => {

  setTimeout(() => {
    resolve();
  }, 3000);

});

let p2 = new Promise((resolve, reject) => {

  setTimeout(() => {
    resolve();
  }, 3000);

});

Promise.all([p1,p2]).then( ()=> {
  this.spinner.hide();
})
1
On

You might want to use forkJoin operator, in this case you will enter in this state when all requests are completed and then you will hide your loading spinner