简体   繁体   English

如何在 RXJS 和 Angular 中订阅或合并新的 Observable

[英]How can I subscribe or merge new Observable in RXJS and Angular

I have a service that always returns Observable<T> , and I cannot change the code of this service.我有一个总是返回Observable<T>的服务,我无法更改该服务的代码。

Supposed I have a button, whenever the button is clicked, I call the method in the service, and it returns a new Observable.假设我有一个按钮,每当单击该按钮时,我都会调用服务中的方法,它会返回一个新的 Observable。 How can I update the new data to UI?如何将新数据更新到 UI?

Source code and playground on StackBlitz StackBlitz 上的源代码和游乐场

app.component.ts

import { Component, Injectable, OnInit } from '@angular/core';
import { Observable, of } from 'rxjs';

@Injectable()
export class Service {
  // Cannot change the code in this class
  public getRandom(): Observable<number> {
    return of(Math.random());
  }
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
  constructor(private service: Service) {}

  public random: number = 0;
  public random$: Observable<number> = new Observable<number>();

  ngOnInit(): void {
    this.random = 0;
  }

  buttonClick(): void {
    // how can I update the random with this.service.getRandom()?
    console.log('button clicked')
  }
}

app.component.html

<h1>{{random}}</h1>

<button (click)="buttonClick()">Get new Random number</button>

I highly recommend using the reactive approach:我强烈建议使用反应式方法:

HTML HTML

<ng-container *ngIf="(random$ | async) as theRandomNumber" >
  <h1>{{ theRandomNumber }}</h1>
</ng-container>

<button (click)="buttonClick()">Get new Random number</button>

ts TS

export class AppComponent implements OnInit {
  random$: Observable<number>!; // no need to initialize it

  constructor(private service: Service) {}
  
  ngOnInit(): void {}

  buttonClick(): void {
     this.random$ = this.service.getRandom();
  }
}

When you trigger the event click , your public class property random$ will store the observable from your service, then, within your template html, using the async pipe, you subscribe to random$ , and it will react for every click event, with this, you keep your ts file cleaner and simple当您触发事件click时,您的公共 class 属性random$将存储来自您的服务的observable对象,然后,在您的模板 html 中,使用async pipe,您订阅random$ ,它将对每个click事件做出反应,与此,你让你的 ts 文件更干净简单

Now, if for some reason, you need to have that random number within your ts file, you could pipe the observable and still keep this reactive approach:现在,如果出于某种原因,您需要在ts文件中包含该随机数,您可以pipe observable并仍然保持这种反应式方法:

import { tap } from 'rxjs';

export class AppComponent implements OnInit {
  random$: Observable<number>!; // no need to initialize it
  private random!: number;

  constructor(private service: Service) {}

  ngOnInit(): void {}

  buttonClick(): void {
     this.random$ = this.service.getRandom()
     .pipe(tap((theNumber) => this.random = theNumber));
  }
}

One easy way is to convert the Observable to a Promise and use await:一种简单的方法是将 Observable 转换为 Promise 并使用 await:

async buttonClick(): Promise<void> {
    const value = await firstValueFrom(random$);
    console.log('button clicked ' + value);
}

If the Observable emits more than once and you want all values, use.subscribe().如果 Observable 发射不止一次并且你想要所有的值,使用.subscribe()。

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

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