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