Observable 在 display 、 ionic app 和 angular fire 从 firestore 获取值后失去价值

Posted

技术标签:

【中文标题】Observable 在 display 、 ionic app 和 angular fire 从 firestore 获取值后失去价值【英文标题】:Observable looses value after display , ionic app and angular fire to fetch values from firestore 【发布时间】:2018-08-12 20:59:48 【问题描述】:

这是导致问题的行为。 https://media.giphy.com/media/1o1oEgsCSoV9wYcTx2/source.mp4 当我从段向后导航时,值消失了。

该值第一次出现,但随后没有保留。 我还看到有时 observable 也需要花费大量时间来显示或获取值。

这是我的 ts 文件

import  AngularFireAuth  from 'angularfire2/auth';

import  SettingsPage  from './../settings/settings';
import  TranslateService  from '@ngx-translate/core';
import  Component, ChangeDetectionStrategy  from '@angular/core';
import  IonicPage, NavController, NavParams, ModalController, AlertController  from 'ionic-angular';
import  AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument  from 'angularfire2/firestore';
import  Observable  from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import * as firebase from 'firebase';
import  FirestoreService  from './../../services/firestore.service';

/**
 * Generated class for the ProfileMasterPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@IonicPage()
@Component(
  selector: 'page-profile-master',
  templateUrl: 'profile-master.html'
)
export class ProfileMasterPage 
  myuid;
  userRef: AngularFirestoreDocument<any> ;
  details: string = "Info";
  phoneNumbers: Observable<any[]>;
  email: Observable<any[]>;
  web: Observable<any[]>;
  address: Observable<any[]>;
  mypr: Observable<any>;


  constructor(public navCtrl: NavController, public navParams: NavParams, public alertCtrl: AlertController, public modalCtrl: ModalController, public translateService: TranslateService, private afAuth: AngularFireAuth, private fs: FirestoreService) 

   this.myuid = this.afAuth.authState.subscribe(result => this.myuid = result.uid);
   this.translateService.get('DELETE_BUTTON');


  ngOnInit()

    this.userRef = this.fs.doc(`users/$this.myuid`);
   console.log('userRef', this.userRef);

    //this.mypr = userRef.valueChanges();
     this.mypr = this.fs.doc$(this.userRef);


    this.phoneNumbers = this.fs.colWithIds$(this.userRef.collection('phoneNumbers'));

    this.email = this.fs.colWithIds$(this.userRef.collection('email'));

    this.web = this.fs.colWithIds$(this.userRef.collection('website'));

    this.address = this.fs.colWithIds$(this.userRef.collection('address'));
  

Firestore 服务会返回此信息

import  Injectable  from '@angular/core';
import  AngularFirestore, 
  AngularFirestoreCollection, 
  AngularFirestoreDocument 
 from 'angularfire2/firestore';
import  Observable  from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/switchMap';

import * as firebase from 'firebase/app';

type CollectionPredicate<T>   = string |  AngularFirestoreCollection<T>;
type DocPredicate<T>          = string |  AngularFirestoreDocument<T>;

@Injectable()
export class FirestoreService 


  constructor(public afs: AngularFirestore)  

  /// **************
  /// Get a Reference
  /// **************

  col<T>(ref: CollectionPredicate<T>, queryFn?): AngularFirestoreCollection<T> 
    return typeof ref === 'string' ? this.afs.collection<T>(ref, queryFn) : ref
  

  doc<T>(ref: DocPredicate<T>): AngularFirestoreDocument<T> 
    return typeof ref === 'string' ? this.afs.doc<T>(ref) : ref
  



  /// **************
  /// Get Data
  /// **************


  doc$<T>(ref:  DocPredicate<T>): Observable<T> 
    return this.doc(ref).snapshotChanges().map(doc => 
      return doc.payload.data() as T
    )
  

  col$<T>(ref: CollectionPredicate<T>, queryFn?): Observable<T[]> 
    return this.col(ref, queryFn).snapshotChanges().map(docs => 
      return docs.map(a => a.payload.doc.data()) as T[]
    );
  



  /// with Ids
  colWithIds$<T>(ref: CollectionPredicate<T>, queryFn?): Observable<any[]> 
    return this.col(ref, queryFn).snapshotChanges().map(actions => 
      return actions.map(a => 
        const data = a.payload.doc.data();
        const id = a.payload.doc.id;
        return  id, ...data ;
      );
    );
  

最后我的 html 看起来像这样

<ion-content>
    <div>
        <ion-card>
            <ion-img   src="./../../assets/img/nin-live.png "></ion-img>
            <ion-card-content>
                <button ion-button icon-left (click)="mainEdit()">
          <ion-icon name="person"></ion-icon>
        </button>
                <ion-card-title>
                     (mypr | async)?.displayName 
                </ion-card-title>
                <h2>
                     (mypr | async)?.title 
                </h2>
                <p padding>
                     (mypr | async)?.company 
                </p>
                <ion-item> (mypr | async)?.city  </ion-item>
                <ion-item> (mypr | async)?.country  </ion-item>
            </ion-card-content>


        </ion-card>

        <ion-segment [(ngModel)]="details">
            <ion-segment-button value="Info">
                Card
            </ion-segment-button>
            <ion-segment-button value="Details">
                Details
            </ion-segment-button>
        </ion-segment>

        <div [ngSwitch]="details">

            <ion-list *ngSwitchCase="'Info'">

                <ion-item>
                    <ion-icon name="call" item-start></ion-icon>
                     (mypr | async)?.phnumber 
                </ion-item>
                <ion-item>
                    <ion-icon name="mail" item-start></ion-icon>
                     (mypr | async)?.email 
                </ion-item>
                <ion-item>
                    <ion-icon name="link" item-start></ion-icon>
                     (mypr | async)?.website 
                </ion-item>

            </ion-list>
            <ion-list *ngSwitchCase="'Details'">
                <ion-list-header>
                    Phone Numbers
                </ion-list-header>
                <ion-item-sliding *ngFor="let ph of phoneNumbers | async ">
                    <button ion-item (click)="upsert(ph,'phoneNumber')">
                <ion-col>
                    <h3> ph.type :</h3>
                   </ion-col>
              <ion-col>
             <p> ph.phNumber  </p>
             </ion-col>
            </button>
                    <ion-item-options>
                        <button ion-button color="danger" (click)="delete( ph, 'phoneNumber')">
                 'DELETE_BUTTON' | translate 
              </button>
                    </ion-item-options>
                </ion-item-sliding>
                <ion-item>
                    <ion-icon name="add" item-start></ion-icon>
                    <button ion-button color="primary" (click)="upsert(ph=null, 'phoneNumber')">
                  add More..
                </button>
                </ion-item>

并编辑我的 html 以仅使用 2 个异步管道

<ion-icon name="person"></ion-icon>
        </button>
                <div *ngIf="mypr | async as user">
                    <ion-card-title>
                         user.displayName 
                    </ion-card-title>
                    <h2>
                         user.title 
                    </h2>
                    <p padding>
                         user.company 
                    </p>
                    <ion-item> user.city  </ion-item>
                    <ion-item> user.country  </ion-item>
                </div>
            </ion-card-content>
        </ion-card>

        <ion-segment [(ngModel)]="details">
            <ion-segment-button value="Info">
                Card
            </ion-segment-button>
            <ion-segment-button value="Details">
                Details
            </ion-segment-button>
        </ion-segment>

        <div [ngSwitch]="details">

            <ion-list *ngSwitchCase="'Info'">
                <div *ngIf="mypr | async as user">
                    <ion-item>
                        <ion-icon name="call" item-start></ion-icon>
                         user.phnumber 
                    </ion-item>
                    <ion-item>
                        <ion-icon name="mail" item-start></ion-icon>
                         user.email 
                    </ion-item>
                    <ion-item>
                        <ion-icon name="link" item-start></ion-icon>
                         user.website 
                    </ion-item>
                </div>
            </ion-list>

【问题讨论】:

this.fs.docWithRefs$ 的代码是什么?另外,为什么你使用异步管道 5 次而不是一次? 能不能把ngOnInit改成ngOnChanges再测试一下? @BorisLobanov ,我已经对代码进行了更改,它不应该是 docWithRef 而是 doc$ 。但是,它仍然无法正常工作。我还对代码的异步管道进行了更改。但还是没有解决问题 @kucing_terbang, no ngOnChanges 不显示任何数据且不工作 我从来没有说过它会修复它,它只是将 http-calls 的数量从 8 个减少到 1 个。 【参考方案1】:

尝试将异步管道移到选项卡之外,如下所示:

<!-- this should wrap the whole template -->
<ng-container  *ngIf="mypr | async as user">

<!-- some other code of the app -->
<ion-icon name="person"></ion-icon>
    </button>
            <div>
                <ion-card-title>
                     user.displayName 
                </ion-card-title>
                <h2>
                     user.title 
                </h2>
                <p padding>
                     user.company 
                </p>
                <ion-item> user.city  </ion-item>
                <ion-item> user.country  </ion-item>
            </div>
        </ion-card-content>
    </ion-card>

    <ion-segment [(ngModel)]="details">
        <ion-segment-button value="Info">
            Card
        </ion-segment-button>
        <ion-segment-button value="Details">
            Details
        </ion-segment-button>
    </ion-segment>

    <div [ngSwitch]="details">

        <ion-list *ngSwitchCase="'Info'">
            <div>
                <ion-item>
                    <ion-icon name="call" item-start></ion-icon>
                     user.phnumber 
                </ion-item>
                <ion-item>
                    <ion-icon name="mail" item-start></ion-icon>
                     user.email 
                </ion-item>
                <ion-item>
                    <ion-icon name="link" item-start></ion-icon>
                     user.website 
                </ion-item>
            </div>
        </ion-list>

</ng-container>

【讨论】:

甜心,乐于助人!你会考虑投票吗?提前致谢! 是的,我确实投了赞成票,但由于我的声誉较低,因此不考虑:) 哦,谢谢 :) 我也赞成这个问题,希望它对您的评分有所帮助

以上是关于Observable 在 display 、 ionic app 和 angular fire 从 firestore 获取值后失去价值的主要内容,如果未能解决你的问题,请参考以下文章

iOS RxSwift - 如何“断开”一个 observable?

为啥 Angular 将 Observable 用于 HttpClient?

在 Axios 中使用 Redux-Observable 的问题

RxSwift:多次连接到 Connectable Observable

ios在画布上使用display:none绘制图像导致内存泄漏

使用 RxJava 和 Resuable Retrofit 创建 REST 客户端 - Observable