[英]Angular 5 - I retrieve my object from firestore in ngOnInit but my view won't update
Using Angular 5 and firestore. 使用Angular 5和firestore。 I successfully retrieve my document and can see it when I console.log(this.assets) in ngOnInit().
我成功检索了我的文档,并在ngOnInit()中的console.log(this.assets)看到了。 The weird thing is that when my site reloads, if I am quick to get to the view before the console.log() runs, my view renders correctly.
奇怪的是,当我的网站重新加载时,如果在console.log()运行之前快速进入视图,则视图将正确呈现。 But if I wait until I see the console.log(), then click on the link to my view, the view won't load the object that I can see clearly in the console.log().
但是,如果我等到看到console.log(),然后单击指向我的视图的链接,该视图将不会加载在console.log()中可以清楚看到的对象。 I assume that my view is not refreshing after:
this.assets = assets;
我假设我的观点在之后没有刷新:
this.assets = assets;
assets.component.ts: assets.component.ts:
import { Component, OnInit } from '@angular/core';
import {DataService} from '../services/data.service';
import {Asset} from '../models/data.model';
@Component({
selector: 'app-assets',
templateUrl: './assets.component.html',
styleUrls: ['./assets.component.css']
})
export class AssetsComponent implements OnInit {
assets: Asset[];
loadCompleted: boolean = false;
constructor(public data: DataService) {
}
ngOnInit() {
this.loadCompleted = false;
this.data.getAssets().subscribe(
(assets)=>{
this.assets = assets;
console.log("assets.component init")
console.log(assets);
console.log(assets.length);
console.log('2', this.loadCompleted)
},
(error)=> console.log(error),
()=>{
this.loadCompleted = true
console.log("3",this.loadCompleted)
}
)
}
}
Those console.log()'s show the correct object and object.length>0. 这些console.log()显示正确的对象,并且object.length> 0。 (there are 4 objects in my database)
(我的数据库中有4个对象)
assets.component.html: assets.component.html:
<div class="container">
<div class="row">
TEST TEST TEST
<div *ngIf="loadCompleted">
<ul class="list-group" *ngFor="let asset of assets">
<li class="list-group-item">
{{asset.name}}
</li>
</ul>
</div>
</div>
</div>
navbar with /assets link 具有/ assets链接的导航栏
<nav class="navbar navbar-dark bg-dark navbar-expand-lg">
<a routerLink="/home" class="navbar-brand">Finances</a>
<button type="button"
class="btn btn-outline-primary navbar-toggler"
(click)="isCollapsed = !isCollapsed"
[attr.aria-expanded]="!isCollapsed"
aria-controls="collapseMenu">
<span class="navbar-toggler-icon"></span>
</button>
<div id="collapseMenu" class="collapse navbar-collapse" [ngbCollapse]="isCollapsed">
<ul class="navbar-nav mr-auto" *ngIf="af.isLoggedIn">
<li class="navbar-item">
<a routerLink="/home" class="nav-link">Home</a>
</li>
<li class="navbar-item">
<div ngbDropdown class="d-inline-block">
<button class="btn btn-dark nav-link" id="dropdownBasic1" ngbDropdownToggle>Assets</button>
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
<button class="dropdown-item" routerLink="/assets" >Home</button>
<button class="dropdown-item" routerLink="/addAsset" >Add Asset</button>
<button class="dropdown-item">Something else is here</button>
</div>
</div>
</li>
<li class="navbar-item">
<a routerLink="/liabilities" class="nav-link">Liabilities</a>
</li>
<li class="navbar-item">
<a href="#" class="nav-link">Income</a>
</li>
<li class="navbar-item">
<a href="#" class="nav-link">Expenses</a>
</li>
</ul>
<ul class="navbar-nav">
<li class="navbar-item" *ngIf="af.isLoggedIn" >
<a routerLink="/profile" class="nav-link">{{af.user_displayName || af.user_email}}</a>
</li>
<li class="navbar-item" *ngIf="af.isLoggedIn" >
<a routerLink="/profile" class="nav-link">Profile</a>
</li>
<li class="navbar-item" >
<a routerLink="/login" class="nav-link" *ngIf="!af.isLoggedIn">Login/Signup</a>
</li>
<li class="navbar-item">
<a href="" class="nav-link" (click)="logout($event)" *ngIf="af.isLoggedIn">Logout</a>
</li>
</ul>
</div>
</nav>
app-router.module.ts APP-router.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import {HomeComponent} from './home/home.component';
import {AssetsComponent} from './assets/assets.component';
import {LoginComponent} from './login/login.component';
import {ProfileComponent} from './profile/profile.component';
import { AssetsAddAssetComponent} from './assets-add-asset/assets-add-asset.component';
import { LiabilitiesComponent} from './liabilities/liabilities.component';
const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{path: 'home', component: HomeComponent},
{path: 'assets', component: AssetsComponent},
{path: 'login', component: LoginComponent},
{path: 'profile', component: ProfileComponent},
{path: 'liabilities', component: LiabilitiesComponent},
{path: 'addAsset', component: AssetsAddAssetComponent},
]
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
data.service.ts data.service.ts
import { Injectable } from '@angular/core';
import {AngularFirestore, AngularFirestoreDocument, AngularFirestoreCollection} from 'angularfire2/firestore';
import {Observable} from 'rxjs/observable';
import {Asset} from '../models/data.model';
@Injectable()
export class DataService {
assetCollection: AngularFirestoreCollection<Asset>;
assets: Observable<Asset[]>;
constructor(public afs: AngularFirestore) {
//this.assets = this.afs.collection('assets').valueChanges();
this.assets = this.afs.collection('assets').snapshotChanges().map(changes=>{
return changes.map(a=>{
const data = a.payload.doc.data() as Asset;
data.id = a.payload.doc.id;
return data;
})
})
}
getAssets(){
return this.assets;
}
addAsset(asset: Asset){
this.afs.collection('assets').add(asset);
}
}
Asset Interface: 资产接口:
export interface Asset {
id?: string;
name?: string;
value?: number;
}
This looks like an old-fashioned RxJS problem. 这看起来像一个老式的RxJS问题。 Your
getAssets()
call returns an observable -- this.assets
. 您的
getAssets()
调用返回一个可观察到的this.assets
。 Since this.assets
is in a singleton service (will only be initialized once) events will not be duplicated for each new subscriber. 由于
this.assets
在单例服务中(将仅初始化一次), 因此不会为每个新订户重复事件。 In other words, if when you browse to your new page this.assets
has already been subscribed too, the second subscriber will not receive any events. 换句话说,如果您浏览到新页面时
this.assets
也已经被订阅,则第二个订阅者将不会收到任何事件。
Fortunately this is easy to fix. 幸运的是,这很容易解决。
this.assets = this.afs.collection('assets').snapshotChanges().map(changes=>{
return changes.map(a=>{
const data = a.payload.doc.data() as Asset;
data.id = a.payload.doc.id;
return data;
})
})
// This will cache the last value and reemit it to new subscribers
.publishReplay(1)
.refCount();
Depending on your version of RX, another option would be to use a ReplaySubject
. 根据您的RX版本,另一种选择是使用
ReplaySubject
。
@Injectable()
export class DataService {
assetCollection: AngularFirestoreCollection<Asset>;
// Will automatically cache the last event for you.
assets = new ReplaySubject<any>(1);
constructor(public afs: AngularFirestore) {
//this.assets = this.afs.collection('assets').valueChanges();
this.afs.collection('assets').snapshotChanges().map(changes=>{
return changes.map(a=>{
const data = a.payload.doc.data() as Asset;
data.id = a.payload.doc.id;
return data;
})
}).subscribe(data => {
this.assets.next(data);
})
}
getAssets(){
return this.assets;
}
addAsset(asset: Asset){
this.afs.collection('assets').add(asset);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.