Angular 2订阅获取帖子数据后HTML视图未渲染问题
解决Angular帖子数据已获取但视图不渲染的问题
嘿,我看你遇到的问题是控制台能拿到posts数据,但视图死活不更新,连{{posts | json}}都显示空数组——这情况我之前用AngularFire的时候也碰到过,大概率是变更检测没触发,或者你没正确处理AngularFire返回的Observable数据。给你几个针对性的解决方案:
1. 用Async管道(最推荐的做法)
Angular的async管道简直是处理异步数据的神器,它会自动帮你完成订阅、取消订阅,还能自动触发变更检测。你不用手动写subscribe了,直接把Observable绑定到模板就行:
组件代码修改:
// 先定义一个Observable类型的变量,代替原来的普通数组 posts$: Observable<any[]>; ngOnInit() { this.loadPosts(this.path, this.opts); } loadPosts(path, opts?) { // 直接把getPosts返回的Observable赋值给posts$,不用手动subscribe this.posts$ = this.getPosts(path, opts); } getPosts(path, opts?: any) { opts ? opts.query.limitToFirst = this.scrollDistance : opts = { query: { orderByChild: "order", startAt: this.offset, limitToFirst: this.scrollDistance } } // 重点:加上valueChanges(),这样才能拿到实际的数据数组 // 如果需要包含每条数据的key,可以换成snapshotChanges() return this.afm.list(path, opts).valueChanges(); }
模板代码修改:
<!-- 用async管道自动订阅Observable --> <div *ngFor="let post of posts$ | async; let i=index" class="post-item"> <div class="card infinite-scroll postContainer"> <app-post-item [post]="post"></app-post-item> <app-comment-loader [user]="user" [post]="post"></app-comment-loader> </div> <img class="banner2" *ngIf="i==0" src="assets/images/ads-banner2.gif" alt="banner2"> </div>
2. 手动触发变更检测(如果非要手动subscribe)
要是你不想用async管道,那得确保subscribe里的赋值能让Angular知道数据变了。有时候AngularFire的回调会跑在变更检测上下文之外,这时候就得手动触发:
组件代码修改:
// 先导入ChangeDetectorRef import { ChangeDetectorRef } from '@angular/core'; // 注入到组件里 constructor(private cd: ChangeDetectorRef) {} posts: any[] = []; // 记得初始化空数组 loadPosts(path, opts?) { this.getPosts(path, opts).subscribe((posts: any[]) => { this.posts = posts; // 手动标记组件需要检测变更 this.cd.markForCheck(); // 要是markForCheck没用,试试this.cd.detectChanges(); 看你组件的变更检测策略 }); } getPosts(path, opts?: any) { opts ? opts.query.limitToFirst = this.scrollDistance : opts = { query: { orderByChild: "order", startAt: this.offset, limitToFirst: this.scrollDistance } } // 同样要加valueChanges()拿到实际数据 return this.afm.list(path, opts).valueChanges(); }
3. 先确认posts变量的初始化
虽然你说显示空数组,但还是要确认下组件里有没有初始化posts为数组:
posts: any[] = [];
如果初始值是undefined,*ngFor可能会悄悄报错,导致视图不渲染。
为啥你原来的代码不行?
原代码里this.afm.list(path, opts)返回的是AngularFireList,它的subscribe回调里的posts其实不是你要的数组——你得用valueChanges()才能拿到实际的帖子数据数组。另外,手动subscribe的时候,回调可能跑在Angular的变更检测周期之外,导致视图不知道数据已经更新了。
建议先试第一种方案,async管道是Angular处理异步数据的最佳实践,能省掉很多麻烦。
内容的提问来源于stack exchange,提问作者İbrahim Dolapci
相关产品推荐
相关产品推荐

