Angularfire2 Firestore数据导航后不显示,Async Pipe在MatTable中如何放置?
我来帮你搞定这个问题!你遇到的导航返回后数据不显示的问题,核心是没有正确管理Firestore Observable的订阅,而Async Pipe正好能帮我们自动处理订阅的创建与销毁,同时完美适配Angular Material Table。下面给你两种可行的解决方案,推荐第一种更简洁实用的方式:
方案1:使用Async Pipe结合MatTableDataSource(推荐)
这种方式既能利用Async Pipe自动管理订阅,又能保留Material Table的排序、分页功能。
步骤1:修改组件代码
去掉自定义的FirebaseDataSource,改用官方的MatTableDataSource,并通过Observable管理数据:
import { Component, OnInit, ViewChild} from '@angular/core'; import {MatTableDataSource, MatSort, MatPaginator} from '@angular/material'; import { Router } from '@angular/router'; import { DataService } from '../../services/data.service'; import { Observable } from 'rxjs'; import { merge } from 'rxjs'; import { map } from 'rxjs/operators'; @Component({ selector: 'app-data-preview', templateUrl: './data-preview.component.html', styleUrls: ['./data-preview.component.css'] }) export class DataPreviewComponent implements OnInit { displayedColumns = ['nom', 'prenom', 'telephone', 'secteur', 'departement', 'commune', 'typeF', 'statut']; dataSource = new MatTableDataSource<any>([]); data$: Observable<any[]>; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; constructor(private router: Router, private dataService: DataService) { } ngOnInit() { // 从服务获取Firestore数据的Observable this.data$ = this.dataService.getData(); // 订阅数据变化,更新数据源 this.data$.subscribe(datas => { this.dataSource.data = datas; }); } ngAfterViewInit() { // 绑定分页器和排序器 this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; // 监听排序和分页变化,实时处理数据 merge(this.sort.sortChange, this.paginator.page) .pipe( map(() => { let processedData = [...this.dataSource.data]; // 处理排序 if (this.sort.active && this.sort.direction) { processedData = processedData.sort((a, b) => { const isAsc = this.sort.direction === 'asc'; switch (this.sort.active) { case 'nom': return a.nom.localeCompare(b.nom) * (isAsc ? 1 : -1); case 'prenom': return a.prenom.localeCompare(b.prenom) * (isAsc ? 1 : -1); // 其他需要排序的字段可以在这里补充 default: return 0; } }); } // 处理分页 const startIndex = this.paginator.pageIndex * this.paginator.pageSize; return processedData.slice(startIndex, startIndex + this.paginator.pageSize); }) ) .subscribe(result => { this.dataSource.data = result; }); } }
步骤2:修改模板代码
直接在mat-table上使用Async Pipe绑定数据(或者保持原模板,因为我们已经通过订阅更新了dataSource,两种方式都可行):
<section class="tableSize"> <div class="example-container mat-elevation-z8"> <div class="example-header"> </div> <mat-table #table [dataSource]="data$ | async" matSort> <!-- 列定义保持不变 --> <ng-container matColumnDef="nom"> <mat-header-cell *matHeaderCellDef mat-sort-header> Nom </mat-header-cell> <mat-cell *matCellDef="let element" [routerLink]="['/data/'+element.id]"> {{element.nom}} </mat-cell> </ng-container> <ng-container matColumnDef="prenom"> <mat-header-cell *matHeaderCellDef mat-sort-header> Prénom </mat-header-cell> <mat-cell *matCellDef="let element" [routerLink]="['/data/'+element.id]"> {{element.prenom}} </mat-cell> </ng-container> <!-- 其他列定义省略 --> <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row> </mat-table> <mat-paginator #paginator [pageSize]="10" [pageSizeOptions]="[10, 20]"> </mat-paginator> </div> </section>
方案2:修复自定义DataSource(适合想保留原有结构的场景)
如果你想继续使用自己的FirebaseDataSource,只需要完善它的订阅管理逻辑:
import { DataSource } from '@angular/cdk/collections'; import { Observable, Subscription } from 'rxjs'; import { DataService } from '../../services/data.service'; export class FirebaseDataSource extends DataSource<any> { private dataSubscription: Subscription; constructor(private dataService: DataService) { super(); } connect(): Observable<any[]> { const data$ = this.dataService.getData(); // 保存订阅实例,用于销毁时取消订阅 this.dataSubscription = data$.subscribe(); return data$; } disconnect(): void { // 组件销毁时取消订阅,避免内存泄漏 if (this.dataSubscription) { this.dataSubscription.unsubscribe(); } } }
然后在模板里给dataSource加上Async Pipe:
<mat-table #table [dataSource]="dataSource | async" matSort>
关键注意事项
- 移除
ngOnDestroy里错误的订阅代码(你之前写的console.log.apply(datas)是语法错误,而且在组件销毁时订阅毫无意义)。 - Async Pipe会自动在组件销毁时取消订阅,在组件重建(导航返回)时重新订阅,这样就能自动重新获取Firestore数据。
- 如果你的
dataService.getData()返回的是Firestore的valueChanges()或snapshotChanges(),这些都是冷Observable,每次订阅都会重新拉取数据,正好满足导航返回的需求。
内容的提问来源于stack exchange,提问作者RxDev
相关产品推荐
相关产品推荐

