Angular-cli 13.3.7获取Firebase数组报this.data未定义求解
问题根因
你遇到的this.data is undefined报错由以下问题导致:
snapshotChanges()是异步Observable对象,你写在subscribe外的console.log(this.data)会在Firebase返回数据前执行,此时data属性尚未被赋值,自然拿到undefined- 组件中
data属性没有设置初始值,Angular首次渲染模板时访问该属性会直接抛类型错误 - 你直接把
snapshotChanges()返回的元数据对象赋值给了data,没有解析payload里的实际业务数据,就算赋值成功也拿不到你存的学生字段 - 附带的Service层bug:
AddStudent方法依赖的studentsRef没有默认初始化,未调用GetStudentsList直接调用新增会报空指针;GetSudent方法名拼写错误、返回值写错对象;UpdateStudent没有指定要更新的记录ID,执行会直接报错。
修复步骤
1. 修正组件异步逻辑,正确解析返回数据
先给data设置空数组初始值,把所有依赖返回数据的逻辑放到subscribe回调内部,同时解析snapshot携带的key和业务字段:
// add-student.component.ts 修正后的相关代码 export class AddStudentComponent implements OnInit { public studentForm: FormGroup; somthing: any; somestuden: Student[]; avilableor: boolean = true; // 给data设置初始空数组,避免模板渲染时报undefined data: any[] = []; some: any[]; constructor( public crudApi: CurdService, public fb: FormBuilder, ) {} ngOnInit() { this.studenForm(); // 无需重复调用GetStudentsList,直接链式调用即可 this.crudApi.GetStudentsList().snapshotChanges().subscribe(records => { // 解析每条记录的key和实际存储的学生数据 this.data = records.map(record => ({ key: record.key, // Firebase自动生成的唯一ID,后续编辑/删除必须用到 ...record.payload.val() // 展开你存储的username/fullname/email/note字段 })); // 所有要用到this.data的逻辑必须写在subscribe回调内 console.log('成功获取学生列表:', this.data); }); } // 其余原有方法保持不变即可 }
2. 修复Service层的逻辑漏洞和笔误
// curd.service.ts 修正后完整代码 import { Injectable } from '@angular/core'; import { Student } from './student'; import { AngularFireDatabase, AngularFireList, AngularFireObject, } from '@angular/fire/compat/database'; @Injectable({ providedIn: 'root' }) export class CurdService { studentsRef: AngularFireList<any>; studentRef: AngularFireObject<any>; constructor (private db: AngularFireDatabase){ // 构造函数初始化列表ref,避免新增操作时空指针 this.studentsRef = this.db.list('students-list'); } AddStudent(student: Student){ this.studentsRef.push({ username: student.username, fullname: student.fullname, email: student.email, note: student.note, }); } // 修正方法名拼写错误,返回对应单条记录的ref GetStudent(id: string){ this.studentRef = this.db.object('students-list/' + id); return this.studentRef; } GetStudentsList() { this.studentsRef = this.db.list('students-list'); return this.studentsRef; } // 补充id参数,指定要更新的记录 UpdateStudent(id: string, student: Student) { this.studentRef = this.db.object('students-list/' + id); this.studentRef.update({ username: student.username, fullname: student.fullname, email: student.email, note: student.note, }); } DeleteStudent(id: string) { this.studentRef = this.db.object('students-list/' + id); this.studentRef.remove(); } }
更简便的数据获取方式
如果你不需要拿到每条记录的Firebase key(不推荐,删改操作必须依赖key),可以直接用valueChanges()方法获取纯业务数据数组,不需要手动解析payload:
// 组件中使用valueChanges的示例 this.crudApi.GetStudentsList().valueChanges().subscribe(students => { // 直接拿到学生对象数组,没有额外元数据 this.data = students as any[]; console.log(this.data); });
注意事项
- 所有AngularFire返回的Observable都是异步执行的,只有subscribe回调内部能拿到赋值后的数据,回调外的代码会在数据返回前执行,永远拿不到最新值
- 模板中渲染
data时建议搭配*ngIf="data.length"判断数据加载完成后再渲染列表,避免空值报错 - 组件销毁时要取消订阅,避免内存泄漏,可以用
takeUntil销毁钩子,或者直接用Angular的async管道自动管理订阅。
内容的提问来源于stack exchange,提问作者zTzyrant
相关产品推荐
相关产品推荐

