我如何在 RXJS 和 Angular 中订阅或合并新的 Observable
How can I subscribe or merge new Observable in RXJS and Angular
我有一项服务总是 returns Observable<T>
,我无法更改此服务的代码。
假设我有一个按钮,每当单击该按钮时,我都会调用服务中的方法,它 returns 一个新的 Observable。如何将新数据更新为 UI?
Source code and playground on 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>
一种简单的方法是将 Observable 转换为 Promise 并使用 await:
async buttonClick(): Promise<void> {
const value = await firstValueFrom(random$);
console.log('button clicked ' + value);
}
如果 Observable 发出不止一次并且您想要所有值,请使用 .subscribe()。
我强烈建议使用反应式方法:
HTML
<ng-container *ngIf="(random$ | async) as theRandomNumber" >
<h1>{{ theRandomNumber }}</h1>
</ng-container>
<button (click)="buttonClick()">Get new Random number</button>
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();
}
}
当您触发事件 click
时,您的 public class 属性 random$
将从您的服务中存储 observable
,然后,在你的模板 html 中,使用 async
管道,你订阅 random$
,它将对每个 click
事件做出反应,这样,你可以保持你的 ts 文件更干净简单
现在,如果出于某种原因,您需要在 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));
}
}
我有一项服务总是 returns Observable<T>
,我无法更改此服务的代码。
假设我有一个按钮,每当单击该按钮时,我都会调用服务中的方法,它 returns 一个新的 Observable。如何将新数据更新为 UI?
Source code and playground on 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>
一种简单的方法是将 Observable 转换为 Promise 并使用 await:
async buttonClick(): Promise<void> {
const value = await firstValueFrom(random$);
console.log('button clicked ' + value);
}
如果 Observable 发出不止一次并且您想要所有值,请使用 .subscribe()。
我强烈建议使用反应式方法:
HTML
<ng-container *ngIf="(random$ | async) as theRandomNumber" >
<h1>{{ theRandomNumber }}</h1>
</ng-container>
<button (click)="buttonClick()">Get new Random number</button>
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();
}
}
当您触发事件 click
时,您的 public class 属性 random$
将从您的服务中存储 observable
,然后,在你的模板 html 中,使用 async
管道,你订阅 random$
,它将对每个 click
事件做出反应,这样,你可以保持你的 ts 文件更干净简单
现在,如果出于某种原因,您需要在 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));
}
}