Angular 2+ 有条件刷新实时数据而不刷新页面

Angular 2+ refreshing real time data conditionally without refreshing the page

我从API服务中得到一笔交易,条件是如果交易状态为'pending',继续重新加载并订阅交易,直到交易状态为'completed'或'rejected'。我的代码只在第一次运行,然后下次访问时,页面是空白的,但即使我取消订阅,数据仍在控制台中运行。

这是我的代码:

export class TransactionSummaryComponent implements OnInit, OnDestroy {

  transaction: Models.Transaction = <Models.Transaction>{};

  cancelling: boolean = false;
  goToPayment: boolean = false;

  private dataRefreshSub: Subscription;
  private subscribeToDataSub: Subscription;
  private timer: Observable<any>;

  constructor(
    private route: ActivatedRoute,
    private router: Router,
    private apiService: ApiService,
    private zone: NgZone,
    @Inject(PLATFORM_ID) private platformId: Object) { }

  ngOnInit() {
    if (isPlatformBrowser(this.platformId)) {
      this.getTransaction();
    }
  }

  getTransaction() {
    this.route.paramMap
    .switchMap((params: ParamMap) => this.apiService.getTransaction(params.get('id')))
    .subscribe((transaction: Models.Transaction) => {
      this.transaction = transaction;

      if (this.transaction.status === 'Pending') {
        this.refreshData();
      }
    });
  }

  refreshData() {
    this.dataRefreshSub = this.route.paramMap
      .switchMap((params: ParamMap) => this.apiService.getTransaction(params.get('id')))
      .subscribe((transaction: Models.Transaction) => {
        this.transaction = transaction;
        this.subscribeToData();
      });
  }

  subscribeToData() {
    this.zone.runOutsideAngular(() => {
      NgZone.assertNotInAngularZone();
      this.timer = Observable.timer(1, 5000);
      this.subscribeToDataSub = this.timer
        .subscribe(() => {
          this.refreshData();
        });
    });
  }

  ngOnDestroy() {
    if (this.dataRefreshSub !== undefined) {
      this.dataRefreshSub.unsubscribe();
    }
    if (this.subscribeToDataSub !== undefined) {
      this.subscribeToDataSub.unsubscribe();
    }
  }
}

我想不出没有副作用的解决方案,但我认为它可能对您有所帮助。 Rxjs 有一个 retry() 运算符,它会在它抛出时为你重新运行订阅。所以我会这样做:

getTransaction() {
    this.route.paramMap
        .switchMap((params: ParamMap) => this.apiService
            .getTransaction(params.get('id'))
            .do(transaction => this.transaction = transaction) // Bad side effect here, I'm not sure how can this be cleaned out.
            .map(transaction => {
                if(transaction.status === 'Pending') {
                    throw 'Pending';
                }
                return transaction;
            })
            // use .retry(N) to retry at most N times. This will infinitely retry
            .retryWhen(errors => errors)
        )
        .subscribe((transaction: Models.Transaction) => {
            // Here transaction will be 'Completed' or 'Rejected'
        });
}

有了这个,理论上您可以删除所有其他订阅。