简体   繁体   中英

Replacing a setTimeout() in an Angular Reactive Form with an Observable

I want to replace a setTimout() with an Observable in an Angular reactive form.

I have a grandchild component that serves a section of a larger reactive form, receives an array of data objects from an API endpoint, packs that data into a Form Array, and submits it to the form. This works well.

The problem is that the asynchronous nature of our API endpoints causes the form data of this grandchild component to render old data before the new data can initialize itself and clear out the old data and repopulate the new data. We've solved this with a setTimout() of 500 ms. It works well on the front end.

The problem is that the setTimeout() is causing issues with our e2e testing failing because it completes the test before the data is loaded. Plus, a timeout is not a long term solution to this async issue... especially if the data could occasionally take longer than 1/2 second (not a usual case, but definitely plausible).

I'm hoping to replace my timeout with an observable as a better solution that won't block our tests and can handle async much more safely. Problem is that I cannot get the observable to work and I'm still an RxJS novice.

Here is the original function with the timeout that is currently running:

setTimeout(() => {
      this.dataRow = [];
      for (let item of this.data.row) {
        this.dataRow.push(item);
      }
    }, 500);

Here is my attempt to recreate with an Observable:

this.dataRow = [];
   this.dataEmitter = from(this.data.row).pipe(delay(1000)).subscribe(data => this.dataRow.push(data);)

My code creates a data stream, but doesn't seem to work the same as the timeout. How can I accomplish this? Is this even the correct way to approach this problem?

EDIT:

this.dataEmitter = of(this.data.row).pipe(delay(1000)).subscribe(row => {
  for (let item of row) {
    this.dataRow.push(item);
  }
}

delay(1000) delays by 1 sec. for every emit. And your snippet is not correct - you can't push(row) because row is undefined (as seen in the snippet).

so if this.data.row is an Object, you need to make it iterable (like an array) if you want to emit this.data.row in "peaces".

But if you just want to get rid of setTimeout :

this.dataEmitter = from([this.data.row]).pipe(delay(1000)).subscribe(row => {
  for (let item of row) {
    this.dataRow.push(item);
  }
}

Your code would be like this:

this.dataRow = []

of(this.data.row)
 .pipe(delay(500))
 .subscribe(data => {
   for(let item of data) {
     this.dataRow.push(item);
   }
 }) 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM