Angular2. How can I check if an observable is completed?

后端 未结 6 528
轮回少年
轮回少年 2020-12-09 08:39

In my page there is a button that generates a report. That report needs data that is loaded using a http call to a rest endpoint when the page is loaded, but I do not have a

相关标签:
6条回答
  • 2020-12-09 09:14

    You can do this by using onCompleted callback in subscription. For example, let's say you show loading bar when user press report button;

    loadCompanies(): void {
         this._companyService.getCompanies().subscribe(
              response => {
                   this.companiesModel = response;
              },
              err => {
                   console.log(err);
                   //closeLoadingBar();
              },
              () => {
                   //do whatever you want
                   //closeLoadingBar()
              }
         )
    }
    
    generateReport() {
        //showLoadingBar()
        this.loadCompanies();
    }
    

    If you get error from your http call, onCompleted method will not be invoked, only onError will be invoked. If it is successful, onCompleted method will be called after your onNext method.

    Here is the documentation for subscribe. I hope it helps!

    0 讨论(0)
  • 2020-12-09 09:17

    One more solution:

    Actually subscribe function takes three parameters:

    onNext onError onCompleted

    this._companyService.getCompanies().subscribe(
        (response) => { this.companiesModel = response; },
        (err) => { console.log(err) },
        (finally) => { console.log('finally') }
    );
    
    0 讨论(0)
  • 2020-12-09 09:21

    Method

    finally()
    

    Invokes a specified action after the source observable sequence terminates gracefully or exceptionally.

    https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/finally.md

    0 讨论(0)
  • 2020-12-09 09:29

    The solution I came up with is to use a shared observable, save the request as a hot observable that way when the report button is clicked it will wait for the request or immediately generate if the request is complete.

    public companiesModel: Company[];
    
    /** pending request, hot Observable (will emit immediately if complete) */
    private companiesRequest: Observable<Company[]>;
    
    constructor(
      private _companyService: CompanyService
    ) {}
    
    public ngOnInit(): void {
      this.loadCompanies();
    }
    
    public generateReport(): void {
      if (this.companiesRequest) {
        // will not make an other network request
        this.companiesRequest.subscribe(
          response => {
            // action using companiesModel.
          },
          err => console.log(err)
        );
      }
    }
    
    private loadCompanies(): void {
      this.companiesRequest = this._companyService.getCompanies().pipe(shareReplay());
      this.companiesRequest.subscribe(
        response => {
          this.companiesModel = response;
        },
        err => console.log(err)
      );
    }
    

    https://stackblitz.com/edit/check-if-an-observable-is-completed?file=src%2Fapp%2Fapp.component.ts

    Update: You could take it one step further and make the UI async https://stackblitz.com/edit/check-if-an-observable-is-completed-async-ui?file=src%2Fapp%2Fapp.component.html

    0 讨论(0)
  • 2020-12-09 09:33

    In this kind of scenarios it is very useful to use concatMap operator to guarantee to execute the next operation only when the previous has done.

    loadCompanies(): void {
        this._companyService.getCompanies()
        .concatMap(companyList => this.getObservableGenerateReport(companyList))
        .subscribe(
            response => {
                this.companiesModel = response;
            },
            err => console.log(err)
        );
    }
    
    
    //Create observable to generate the report
    getObservableGenerateReport(response: any): Observable<myReportList> {
    
        return Observable.create(observer => {
    
          if (generateReport().isSuccessful) {
            observer.next(myReportList);
            observer.complete();
          } else {
            console.log(err, 'Ups, something was wrong!');
            observer.next({});
            observer.complete();
          }
    
        });
      }
    
    0 讨论(0)
  • 2020-12-09 09:36

    If you're doing this to debug, the simplest solution is to use the complete argument of tap:

    tap(next: null, error: null, complete: () => void)
    

    With a source source$ it would look like this:

    source$.pipe(
      tap(undefined, undefined, console.log)
    );
    
    0 讨论(0)
提交回复
热议问题