简体   繁体   English

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

[英]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.

相关问题 我的视图不会使用来自Angular5组件的更新数据进行更新 - My View won't update with updated data from my Angular5 component Angular 4:为什么我不能在ngOnInit()中调用公共函数? - Angular 4: why can't I call a public function in my ngOnInit()? 为什么 angular 在 ngOnInit 中创建时说我的对象可以为空? - Why is angular saying my object can be null when creating in ngOnInit? 在 ngOnInit 中等待来自 get 调用的数据时,如何显示微调器? (角度 15) - How can i show a spinner while waiting for data from a get call inside my ngOnInit ? (Angular 15) Angular 6-ngOnInit中的函数不会触发 - Angular 6 - functions in ngOnInit won't trigger 如何使用 Angular Fire 从我的 Angular 代码中检索插入到 FireStore 集合中的文档的 UID? - How to retrieve the UID of a document inserted into a FireStore collection from my Angular code using Angular Fire? 添加或编辑项目后,Angular 2不会更新我的视图 - Angular 2 doesn't update my view after I add or edit item 如何使用Ionic4 / Angular在嵌套的Firestore数据库中检索所有用户的数据 - How do I retrieve the data of ALL of the users in my nested Firestore database using Ionic4/Angular Angular:在 ngOnInit() 我的 rxjs 重新加载组件时功能不运行 - Angular: in ngOnInit() My rxjs Fucntion dont run when I reload my component 角度点击不适用于我的 div - angular click won't work on my div
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM