You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:04:50