使用Angular 5和firestore。我成功检索了我的文档,并且当我在ngOnInit()中的console.log(this.assets)时可以看到它。奇怪的是,当我的网站重新加载时,如果我在之前快速访问视图,则运行console.log(),我的视图呈现正确。但是,如果我等到看到console.log(),然后单击指向我视图的链接,视图就不会加载我在console.log()中可以清楚看到的对象。我认为在this.assets = assets;
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)
}
)
}
}
那些console.log()显示正确的对象和object.length> 0。 (我的数据库中有4个对象)
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
<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
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
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);
}
}
资产界面:
export interface Asset {
id?: string;
name?: string;
value?: number;
}
答案 0 :(得分:1)
这看起来像是老式的RxJS问题。您的getAssets()
调用会返回一个可观察的 - this.assets
。由于this.assets
处于单件服务中(仅初始化一次),因此每个新订户不会复制的事件。换句话说,如果您浏览到新页面this.assets
也已订阅,则第二个订阅者将不会收到任何事件。
幸运的是,这很容易解决。
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();
根据您的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);
}
}