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

Angular 6自定义对象数组Observable仅加载一次问题求助

Angular 6 + AngularFire2 Firestore: List Fails to Load After Route Navigation

问题场景

我最近在用Angular 6搭配angularfire2 firestore开发应用时,碰到了一个头疼的问题:

  • 首次访问/list路由时,对象列表能正常渲染展示
  • 切换到/Home路由后再切回/list,列表直接不显示,控制台也没有任何报错信息
  • 只有手动按F5刷新页面,列表才会重新出现

原服务代码

import { AngularFirestoreCollection, AngularFirestoreDocument, AngularFirestore } from 'angularfire2/firestore';
import { Personagem } from './../model/personagem';
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class PersonagemService {
  personagens: Observable;
  personagemColl: AngularFirestoreCollection;
  personagemDoc: AngularFirestoreDocument;

  constructor(private afs: AngularFirestore) {
    this.personagemColl = this.afs.collection('personagem', ref=> ref.orderBy('nome', 'asc'));
    this.personagens = this.personagemColl.snapshotChanges().map(changes=> {
      return changes.map(p => {
        const data = p.payload.doc.data() as Personagem;
        data.id = p.payload.doc.id;
        return data;
      });
    });
  }

  getPersonagens() {
    return this.personagens;
  }

  addPersonagem(personagem: Personagem) {
    this.personagemColl.add(personagem);
  }

  deletePersonagem(personagem: Personagem) {
    this.getPersonagemDoc(personagem)
    this.personagemDoc.delete();
  }

  updatePersonagem(personagem: Personagem) {
    this.getPersonagemDoc(personagem)
    this.personagemDoc.update(personagem);
  }

  getPersonagemDoc(personagem: Personagem) {
    return this.personagemDoc = this.afs.doc(`personagem/${personagem.id}`);
  }
}

原组件代码

import { Router } from '@angular/router';
import { PersonagemService } from './../../services/personagem.service';
import { Component, OnInit } from '@angular/core';
import { Observable } from '@firebase/util';
import { Personagem } from '../../model/personagem';

@Component({
  selector: 'app-listar-personagem',
  templateUrl: './listar-personagem.component.html',
  styleUrls: ['./listar-personagem.component.css']
})
export class ListarPersonagemComponent implements OnInit {
  personagens: Personagem[];

  constructor(private personagemServ: PersonagemService, private router: Router) { }

  ngOnInit() {
    this.personagemServ.getPersonagens().subscribe(personagens => {
      this.personagens = personagens;
      console.log('lenght', this.personagens.length);
    });
  }
}

问题根源

问题其实出在Angular服务的单例特性上:

  • 因为服务是providedIn: 'root'的单例模式,构造函数只会在应用启动时执行一次
  • 在构造函数中初始化的personagens Observable,第一次被订阅后就进入了"冷态",不会再主动请求Firestore的新数据
  • 当组件第二次进入/list路由时,调用getPersonagens()拿到的是同一个旧Observable,订阅它不会触发新的快照请求,自然拿不到数据

解决后的代码

我调整了服务和组件的代码逻辑,核心是让每次组件请求数据时都拿到一个新的Observable,确保能重新触发Firestore的快照查询:

修改后的服务代码

// 移除全局的personagens Observable声明
personagemColl: AngularFirestoreCollection;
personagemDoc: AngularFirestoreDocument;

constructor(private afs: AngularFirestore) {
  this.personagemColl = this.afs.collection('personagem', ref=> ref.orderBy('nome', 'asc'));
}

getPersonagens$(): Observable {
  return this.personagemColl.snapshotChanges().map(changes=> {
    return changes.map(p => {
      const data = p.payload.doc.data() as Personagem;
      data.id = p.payload.doc.id;
      return data;
    });
  });
}

// add/delete/update等其他方法保持不变

修改后的组件代码

personagens: Personagem[];

constructor(private personagemServ: PersonagemService, private router: Router) { }

ngOnInit() {
  this.personagemServ.getPersonagens$().subscribe(
    personagens => {
      this.personagens = personagens;
    });
}

这样修改后,每次组件进入/list路由执行ngOnInit时,都会调用getPersonagens$()获取新的Observable并订阅,就能重新拿到Firestore的快照数据,路由切换后列表也能正常显示了。

内容的提问来源于stack exchange,提问作者WSouBar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:39:20