Angular Material 6 mat-table集成服务数据问题求助
解决Angular Material表格集成Firebase患者数据服务的问题
我来帮你排查并解决这个Angular Material表格加载服务数据的问题,看了你的代码,主要问题出在服务的数据返回逻辑和组件的订阅处理上,下面一步步来调整:
1. 修复PatientsService的getPatients方法
你的getPatients()目前只是监听Firebase的数据变化,但没有把数据以Observable的形式返回给组件,导致组件订阅后拿不到有效数据。修改服务代码,让它返回可订阅的数据流:
import { Injectable } from '@angular/core'; import { Subject } from 'rxjs/Subject'; import { Patient } from '../models/patient.model'; import * as firebase from 'firebase'; import DataSnapshot = firebase.database.DataSnapshot; import { Observable } from "rxjs"; @Injectable() export class PatientsService { patients: Patient[] = []; patientsSubject = new Subject<Patient[]>(); emitPatients() { // 发送数组副本,避免组件直接修改服务内的原始数据 this.patientsSubject.next([...this.patients]); } savePatients() { firebase.database().ref('/patients').set(this.patients); } // 修改后返回Observable,让组件能订阅数据 getPatients(): Observable<Patient[]> { return new Observable(observer => { firebase.database().ref('/patients') .on('value', (data: DataSnapshot) => { this.patients = data.val() ? data.val() : []; this.emitPatients(); observer.next(this.patients); // 把数据推送给订阅的组件 }, (error) => { observer.error(error); // 传递错误信息 }); }); } getSinglePatient(id: number) { return new Promise( (resolve, reject) => { firebase.database().ref('/patients/' + id).once('value').then( (data: DataSnapshot) => { resolve(data.val()); }, (error) => { reject(error); } ); } ); } // 补充你缺失的removePatient方法,删除后同步更新数据流 removePatient(patient: Patient) { const index = this.patients.findIndex(p => p.nom === patient.nom && p.prenom === patient.prenom); if (index !== -1) { this.patients.splice(index, 1); this.savePatients(); this.emitPatients(); } } }
2. 调整组件代码,正确处理订阅和数据源
你的组件存在订阅未赋值、冗余调用等小问题,调整后确保数据能正确流入MatTable:
import { Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; import { PatientsService } from '../services/patients.service'; import { Patient } from '../models/patient.model'; import { Subscription } from 'rxjs'; import { Router } from '@angular/router'; import { MatPaginator, MatTableDataSource } from '@angular/material'; @Component({ selector: 'app-patient-list', templateUrl: './patient-list.component.html', styleUrls: ['./patient-list.component.scss'] }) export class PatientListComponent implements OnInit, OnDestroy { displayedColumns = ['prenom', 'nom', 'sexe', 'daten']; dataSource = new MatTableDataSource<Patient>(); patientsSubscription: Subscription; // 若需要分页,引用MatPaginator @ViewChild(MatPaginator) paginator: MatPaginator; constructor(private patientsService: PatientsService, private router: Router) {} ngOnInit() { // 订阅服务返回的数据流,更新表格数据源 this.patientsSubscription = this.patientsService.getPatients().subscribe( (patients: Patient[]) => { this.dataSource.data = patients; // 启用分页的话绑定paginator this.dataSource.paginator = this.paginator; }, (error) => { console.error('加载患者数据失败:', error); } ); } onNewPatient() { this.router.navigate(['/patients', 'new']); } onDeletePatient(patient: Patient) { this.patientsService.removePatient(patient); } onViewPatient(id: number) { this.router.navigate(['/patients', 'view', id]); } ngOnDestroy() { // 组件销毁时取消订阅,避免内存泄漏 if (this.patientsSubscription) { this.patientsSubscription.unsubscribe(); } } }
3. 优化HTML模板,处理日期显示
直接显示原始Date对象会影响可读性,用Angular的DatePipe格式化日期,同时可按需添加分页组件:
<div> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <!-- Prénom列 --> <ng-container matColumnDef="prenom"> <th mat-header-cell *matHeaderCellDef> Prénom </th> <td mat-cell *matCellDef="let element">{{element.prenom}}</td> </ng-container> <!-- Nom列 --> <ng-container matColumnDef="nom"> <th mat-header-cell *matHeaderCellDef> Nom de naissance </th> <td mat-cell *matCellDef="let element">{{element.nom}}</td> </ng-container> <!-- 日期列:用DatePipe格式化显示 --> <ng-container matColumnDef="daten"> <th mat-header-cell *matHeaderCellDef> Date de naissance </th> <td mat-cell *matCellDef="let element">{{element.daten | date:'dd/MM/yyyy'}}</td> </ng-container> <!-- Sexe列 --> <ng-container matColumnDef="sexe"> <th mat-header-cell *matHeaderCellDef> Sexe </th> <td mat-cell *matCellDef="let element">{{element.sexe}}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> <!-- 分页组件(可选) --> <mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator> </div>
最后别忘了在你的模块中导入必要的Material模块和CommonModule(DatePipe依赖它):
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MatTableModule } from '@angular/material/table'; import { MatPaginatorModule } from '@angular/material/paginator'; import { PatientListComponent } from './patient-list.component'; @NgModule({ imports: [ CommonModule, MatTableModule, MatPaginatorModule ], declarations: [PatientListComponent] }) export class PatientsModule { }
关键问题总结
- 之前服务的
getPatients()没有返回Observable,导致组件订阅后无法获取数据;修改后服务会实时把Firebase的数据推送给组件。 - 发送Subject时传递数组副本,保持数据流的单向性,避免组件直接修改服务内的原始数据。
- 用
DatePipe格式化日期,提升页面可读性。 - 组件销毁时取消订阅,避免内存泄漏。
内容的提问来源于stack exchange,提问作者user9805953
相关产品推荐
相关产品推荐

