typescript - 在 Angular 的 ts 文件中使用 Async 管道
当我们在 HTML 中使用 async 管道时,我们使用语法 "Products$| async as products"。
如果我想在 ts 文件中使用相同的产品怎么办?这可以做到吗?
答案#1
简单来说,当对象 Products$是可观察数组时,我们可以使用 async 管道,如果你想在 ts 文件中使用,你可以订阅并像下面这样获取数据
Products$.subscribe((products) => {
console.log(Products);
});
答案#2
经过广泛探索,我已经找到了答案,并且希望它能解决你所有的疑问。
对于你的问题没有简明的答案,但我会尽力解释一切。如果你在理解上遇到任何困难,可以随时查找更多信息,然后再问我。
让我们把它看作一个 product.service 文件,它可以包含一个数组,该数组可以是来自 API 端点的 Observable<T>、Subscribable<T> 或 Promise<T>。我们的目标是解析它并在我们的 '.ts' 文件中使用 async pipe 获取其值,这样我们每次就不用手动取消订阅了。
为了明确起见,我也提到了值的类型注解。
这是我们的 product.service.ts 文件,它作为 Angular 依赖注入系统的一部分。因此我们可以在整个应用程序中使用它们。
import { Injectable } from '@angular/core';
import { Observable, shareReplay } from 'rxjs';
import { ProductsList } from '../products.interface';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root',
})
export class ProductsService {
constructor(private http: HttpClient) {}
// You can also use this.
// getProducts$: Observable<ProductsList[]> = this.http.get<ProductsList[]>('/api/rooms').
getRooms$: Observable<ProductsList[]> = this.http.get<ProductsList[]>('/api/products').pipe(shareReplay(1));
}
我尝试使用 AsyncPipe 实现一些逻辑,但它返回了一个空值。这种方法不推荐使用,我很快会解释原因;从
import { AsyncPipe } from '@angular/common';
这是我们在 app.component.ts 组件中的实现。
import {
OnInit,
OnDestroy,
AfterViewInit,
} from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ProductsList } from './products/products.interface';
import { ProductsService } from './products/services/products.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
products$!: ProductsList[] | null;
private destroy$: Subject<void> = new Subject<void>();
constructor(
private productsService: ProductsService,
) {
this.productsService.getProducts$
.pipe(takeUntil(this.destroy$))
.subscribe((products: productsList[]) => {
this.products$ = products;
console.log(this.products$); // Correct Value
});
// console.log(this.products$); // Undefined Value
}
anyOtherFunction(): void {
// console.log(this.products$); // Correct Value
}
ngOnInit(): void {
// console.log(this.products$); // Undefined Value
}
ngAfterViewInit(): void {
// console.log(this.products$); // Undefined Value
}
ngOnDestroy(): void {
// Automatically unsubscribe when the component is destroyed
this.destroy$.next();
this.destroy$.complete();
}
}
在这里你可以看到,this.products$ 在每个生命周期钩子中都是未定义的,因为生命周期钩子在 Angular 中是同步调用的,而 this.products$ 是异步的。因此,要在任何生命周期中获取 this.products$ 的值,我们必须再次订阅它;例如
this.productsService.getProducts$
.pipe(takeUntil(this.destroy$))
.subscribe((products: productsList[]) => {
this.products$ = products;
console.log(this.products$); // Correct Value
});
在这种情况下,我们选择不使用 Angular 的 AsyncPipe,而是手动管理订阅。这意味着我们还需要处理手动取消订阅。
然而,有一个关键的区别。我们不再需要手动取消订阅;当组件被销毁时,它现在会自动发生。我们可以根据需要添加多个订阅者,并且它们将会自动取消订阅。
别忘了添加 ngOnDestroy,请参阅 app.component.ts 文件
ngOnDestroy(): void {
// Automatically unsubscribe when the component is destroyed
this.destroy$.next();
this.destroy$.complete();
}
我们通过使用一个
destroy$主题来管理组件的生命周期,在组件销毁时自动处理订阅清理。在
ngOnInit生命周期钩子中,我们使用takeUntil订阅getProducts$可观察对象。这个订阅被设计为在destroy$subject 发出时自动取消订阅。当数据到达时,它会存储在
products属性中,使其可以在组件的逻辑和模板中随时使用。但在生命周期内例外。当组件被销毁时,
ngOnDestroy钩子会完成destroy$主题,确保任何待处理的订阅都被正确处理。
这种方法提供了与异步相似的订阅管理水平,尽管需要一些手动配置。尽管如此,它有效地防止了内存泄漏,并保证组件销毁时正确清理订阅。
我们可以有多个可观察对象进行订阅
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable, Subject, merge } from 'rxjs';
import { ProductsList } from './products/products.interface';
import { ProductsService } from './products/services/products.service';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit, OnDestroy {
products: ProductsList[] | null = null;
otherData: any; // You can have multiple data properties
private destroy$: Subject<void> = new Subject<void>();
constructor(private productsService: ProductsService, private otherService: OtherService) {}
ngOnInit(): void {
// Combine multiple observables using merge
const products$ = this.productsService.getProducts$.pipe(takeUntil(this.destroy$));
const otherData$ = this.otherService.getOtherData$.pipe(takeUntil(this.destroy$));
// Merge the observables into a single subscription
const combined$ = merge(products$, otherData$);
// Subscribe to the combined observable
combined$.subscribe((data) => {
if (data instanceof ProductsList) {
this.products = data;
} else {
this.otherData = data;
}
});
}
ngOnDestroy(): void {
// Automatically unsubscribe when the component is destroyed
this.destroy$.next();
this.destroy$.complete();
}
}
我们使用 merge 操作符将多个可观察对象(products$和 otherData$)合并为一个可观察对象(combined$)。然后,我们订阅 combined$并根据需要处理不同类型的数据。
OR 你也可以采用 Angular 提供的推荐方式使用 Async Pipe;在 HTML 文件中,你可以使用 async pipe 来处理异步数据绑定。
<ng-container *ngIf="products$ | async as products"> {...} </ng-container>
如果你像我一样,想尝试不同的东西,那么你可以使用第一种方法
