Use an asynchronous pipe to poll Observables?

Scenario:

I have a service that checks a URL every 2 seconds:

export class FooDataService {

...

  public provideFooData() {
    const interval = Observable.interval(2000).startWith(0);
    return interval
      .switchMap(() => this.http.get(this.requestUrl))
      .map(fooData => fooData.json())
  }
}

      

Now I have a component where I want to show the survey data:

export class FooComponent implements OnInit {

  constructor(private fooDataService: FooDataService) {}

  public fooData$: Observable<FooData>;

  ngOnInit() {
    this.fooData$ = this.fooDataService.provideFooData();
  }
}

      

In a component template, I would use an asynchronous pipe to fetch and pass a value along with an additional component:

<foo-data-viewer [data]="fooData$ | async"></foo-data-viewer>

      

The problem with this approach:

The implementation of it like this is not verified with protractor (see my last question on this question or this article ). All code is executed inside ngZone and the protractor will wait for all the jobs in the queue to complete before continuing. But it Observable.interval()

will queue an unlimited number of actions, which will lead to a timeout in the transporter.

Common decision:

The fix I read most often is to use runOutsideAngular

this way:

export class FooComponent implements OnInit, OnDestroy {

  constructor(private ngZone: NgZone,
              private fooDataService: FooDataService) {}

  public fooData: FooData;
  public fooDataSubscription: Subscription<FooData>;

  ngOnInit() {

    this.ngZone.runOutsideAngular(() => {
      this.fooDataSubscription =
        this.fooDataService.provideFooData()
            .subscribe(
               fooData => this.ngZone.run(() => this.fooData = fooData)
            );
    });
  }

  ngOnDestroy(): void {
    this.fooDataSubscription.unsubscribe();
  }
}

      

By starting an interval outside of ngZone, the protractor does not wait for the poll to complete before continuing, and thus does not time out.

This means, however:

  • I cannot use the tube async

    , I need to subscribe manually.
  • I need to manage the subscription manually and clear it myself when the component is destroyed.
  • I can't keep a nice and clean Observable style and the code gets a lot more confusing, especially if I have multiple polling services.

My question is:

Is there a way to keep the functional style of rxjs and keep working with the async pipe (or equivalent) while running the interval outside of ngZone?

I came across this github project which is similar to what I want, but I couldn't get it to work.

I need a working example to leave and re-enter a zone like in my scenario, without having to manage the subscription myself.

+3


source to share





All Articles