简体   繁体   English

角度2。 如何检查可观察对象是否已完成?

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

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 guarantee that they are loaded when the user presses the report button.该报告需要在页面加载时使用对 rest 端点的 http 调用加载的数据,但我不能保证当用户按下报告按钮时它们会被加载。

How can I watch the observable to see if it is completed, and if incomplete, to wait on the action until the http call is completed?我如何观察可观察对象是否已完成,如果未完成,则等待操作直到 http 调用完成? Here is some of the code:这是一些代码:

loadCompanies(): void {
    this._companyService.getCompanies().subscribe(
        response => {
            this.companiesModel = response;
        },
        err => console.log(err)
    );
}
generateReport() {
   // check if observable that loads companies is completed and do the 
   // action using companiesModel.
} 

One option is a flag set in loading companies with values of 'loading' and 'completed', and make a wait in generateReport() until the flag is completed, but I would prefer a solution using the Observable API if possible.一种选择是在加载公司中设置标志,其值为“正在加载”和“已完成”,并在generateReport()中等待直到标志完成,但如果可能,我更喜欢使用Observable API 的解决方案。

You can do this by using onCompleted callback in subscription .您可以通过在subscription中使用onCompleted回调来做到这一点。 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.如果您从 http 调用中收到错误,则不会调用onCompleted方法,只会调用onError If it is successful, onCompleted method will be called after your onNext method.如果成功,将在您的onNext方法之后调用onCompleted方法。

Here is the documentation for subscribe .这是subscribe的文档。 I hope it helps!我希望它有所帮助!

One more solution:另一种解决方案:

Actually subscribe function takes three parameters:实际上 subscribe 函数需要三个参数:

onNext onError onCompleted onNext onError onCompleted

this._companyService.getCompanies().subscribe(
    (response) => { this.companiesModel = response; },
    (err) => { console.log(err) },
    (finally) => { console.log('finally') }
);

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 https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/finally.md

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.在这种情况下,使用concatMap运算符来保证仅在前一个操作完成后才执行下一个操作非常有用。

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();
      }

    });
  }

If you're doing this to debug, the simplest solution is to use the complete argument of tap :如果您这样做是为了调试,最简单的解决方案是使用tapcomplete参数:

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

With a source source$ it would look like this:使用源source$它看起来像这样:

source$.pipe(
  tap(undefined, undefined, console.log)
);

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 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更新:您可以更进一步,使 UI 异步https://stackblitz.com/edit/check-if-an-observable-is-completed-async-ui?file=src%2Fapp%2Fapp.component。网页格式

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 角2。 我该如何使用存在的参数添加附加的queryParam路由? - angular2. how can I make a route append queryParam with exists params? 在angular2中渲染编辑表单。 我如何等待服务中的数据? - Rendering edit forms in angular2. How can I wait for data from service? 如何在订阅完成后从Angular中的promise / observable设置变量? - How can I set a variable from a promise/observable in Angular after the subscription has completed? Angular2。 我可以同时使用ViewChild和@Input吗? - Angular2. Can I use ViewChild and @Input at the same time? 我无法在 angular2 中使用此代码。 如何使用它 - i cant use this code in angular2. how to use it Angular2。 如何在标签“ href”中使用* ngFor设置“ URL”,并在条件*​​ ngIf中设置“ {{theme.name}}”? - Angular2. How can I use *ngFor for set “URL” in the tag “href” and set '{{theme.name}}' in the condition *ngIf? 如何检查可观察的倒数计时器是否已完成? - How to check if observable countdown timer has completed? 角度2。 无法设置班级属性 - Angular2. Can't set class property Angular2。 如何在检查访问后隐藏(无渲染)菜单中的链接? - Angular2. How to hide(no-render) the link in the menu after check access? 角2。 如何防止路由改变 - Angular2. How to prevent route change
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM