繁体   English   中英

Angular 5-我从ngOnInit的firestore中检索了我的对象,但是我的视图不会更新

[英]Angular 5 - I retrieve my object from firestore in ngOnInit but my view won't update

使用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>

具有/ 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

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;
  } 

这看起来像一个老式的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);
  }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM