我用用户名,密码和电子邮件更新功能创建一个配置文件页面。我可以使用“更改电子邮件”和“更改密码”,但是以某种方式将相同的方法应用于“更改名称”却无法正常工作
我确实尝试了一些安全的导航操作符(?),但不起作用。请帮我指出我错了,非常感谢。
profile.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Routes, RouterModule } from '@angular/router';
import { IonicModule } from '@ionic/angular';
import { ProfilePage } from './profile.page';
const routes: Routes = [
{
path: '',
component: ProfilePage
}
];
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
RouterModule.forChild(routes)
],
declarations: [ProfilePage]
})
export class ProfilePageModule {}
profile.page.html
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="/home"></ion-back-button>
</ion-buttons>
<ion-title>Profile Page</ion-title>
<ion-buttons slot="end">
<ion-button (click)="logOut()">
<ion-icon slot="icon-only" name="log-out"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list> <ion-list-header> Personal Information </ion-list-header> </ion-list>
<ion-item (click)="updateName()">
<ion-label>
<ion-grid>
<ion-row>
<ion-col class="text-left" size="5"> Name </ion-col>
<ion-col
class="text-center"
size="7"
*ngIf="userProfile?.firstName || userProfile?.lastName"
>
{{userProfile?.firstName}} {{userProfile?.lastName}}
</ion-col>
<ion-col
size="7"
class="placeholder-profile text-center"
*ngIf="!userProfile?.firstName"
>
<span> Tap here to edit. </span>
</ion-col>
</ion-row>
</ion-grid>
</ion-label>
</ion-item>
<ion-item>
<ion-label class="dob-label">Date of Birth</ion-label>
<ion-datetime
displayFormat="MMM D, YYYY"
pickerFormat="D MMM YYYY"
[(ngModel)]="birthDate"
(ionChange)="updateDOB(birthDate)"
>
</ion-datetime>
</ion-item>
<ion-item (click)="updateEmail()">
<ion-label>
<ion-grid>
<ion-row>
<ion-col class="text-left" size="5"> Email </ion-col>
<ion-col class="text-center" size="7" *ngIf="userProfile?.email">
{{userProfile?.email}}
</ion-col>
<ion-col
size="7"
class="placeholder-profile text-center"
*ngIf="!userProfile?.email"
>
<span> Tap here to edit. </span>
</ion-col>
</ion-row>
</ion-grid>
</ion-label>
</ion-item>
<ion-item (click)="updatePassword()">
<ion-label>
<ion-grid>
<ion-row>
<ion-col class="text-left" size="5"> Password </ion-col>
<ion-col class="text-center" size="7" class="placeholder-profile">
<span> Tap here to edit. </span>
</ion-col>
</ion-row>
</ion-grid>
</ion-label>
</ion-item>
</ion-content>
profile.page.ts
import { Component, OnInit } from '@angular/core';
import { AlertController } from '@ionic/angular';
import { AuthService } from '../../services/user/auth.service';
import { ProfileService } from '../../services/user/profile.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-profile',
templateUrl: './profile.page.html',
styleUrls: ['./profile.page.scss'],
})
export class ProfilePage implements OnInit {
public userProfile: any;
public birthDate: Date;
constructor(
private alertCtrl: AlertController,
private authService: AuthService,
private profileService: ProfileService,
private router: Router
) { }
ngOnInit() {
this.profileService
.getUserProfile()
.get()
.then( userProfileSnapshot => {
this.userProfile = userProfileSnapshot.data();
this.birthDate = userProfileSnapshot.data().birthDate;
});
}
async updateName(): Promise<void> {
const alert = await this.alertCtrl.create({
subHeader: 'Your first name & last name',
inputs: [
{
type: 'text',
name: 'firstName',
placeholder: 'Your first name',
value: this.userProfile.firstName,
},
{
type: 'text',
name: 'lastName',
placeholder: 'Your last name',
value: this.userProfile.lastName,
},
],
buttons: [
{ text: 'Cancel' },
{
text: 'Save',
handler: data => {
this.profileService.updateName(data.firstName, data.lastName);
},
},
],
});
await alert.present();
}
logOut(): void {
this.authService.logoutUser().then( () => {
this.router.navigateByUrl('login');
});
}
updateDOB(birthDate: string): void {
if (birthDate === undefined) {
return;
}
this.profileService.updateDOB(birthDate);
}
async updateEmail(): Promise<void> {
const alert = await this.alertCtrl.create({
inputs: [
{ type: 'text', name: 'newEmail', placeholder: 'Your new email' },
{ name: 'password', placeholder: 'Your password', type: 'password' },
],
buttons: [
{ text: 'Cancel' },
{
text: 'Save',
handler: data => {
this.profileService
.updateEmail(data.newEmail, data.password)
.then(() => {
console.log('Email Changed Successfully');
})
.catch(error => {
console.log('ERROR: ' + error.message);
});
},
},
],
});
await alert.present();
}
async updatePassword(): Promise<void> {
const alert = await this.alertCtrl.create({
inputs: [
{ name: 'newPassword', placeholder: 'New password', type: 'password' },
{ name: 'oldPassword', placeholder: 'Old password', type: 'password' },
],
buttons: [
{ text: 'Cancel' },
{
text: 'Save',
handler: data => {
this.profileService.updatePassword(
data.newPassword,
data.oldPassword
);
},
},
],
});
await alert.present();
}
}
profile.service.ts
import { Injectable } from '@angular/core';
import * as firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
@Injectable({
providedIn: 'root'
})
export class ProfileService {
public userProfile: firebase.firestore.DocumentReference;
public currentUser: firebase.User;
constructor() {
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.currentUser = user;
this.userProfile = firebase.firestore().doc(`/userProfile/${user.uid}`);
}
});
}
getUserProfile(): firebase.firestore.DocumentReference {
return this.userProfile;
}
updateName(firstName: string, lastName: string): Promise<any> {
return this.userProfile.update({ firstName, lastName });
}
updateDOB(birthDate: string): Promise<any> {
return this.userProfile.update({ birthDate });
}
async updateEmail(newEmail: string, password: string): Promise<any> {
const credential: firebase.auth.AuthCredential = firebase.auth.EmailAuthProvider.credential(
this.currentUser.email,
password
);
try {
await this.currentUser
.reauthenticateAndRetrieveDataWithCredential(credential);
this.currentUser.updateEmail(newEmail).then(() => {
this.userProfile.update({ email: newEmail });
});
}
catch (error) {
console.error(error);
}
}
async updatePassword(newPassword: string, oldPassword: string): Promise<any> {
const credential: firebase.auth.AuthCredential = firebase.auth.EmailAuthProvider.credential(
this.currentUser.email,
oldPassword
);
try {
await this.currentUser
.reauthenticateAndRetrieveDataWithCredential(credential);
this.currentUser.updatePassword(newPassword).then(() => {
console.log('Password Changed');
});
}
catch (error) {
console.error(error);
}
}
}
ERROR TypeError: "this.profileService.getUserProfile(...) is undefined"
ERROR Error: "Uncaught (in promise): TypeError: this.userProfile is undefined
答案 0 :(得分:0)
ngOnInit生命周期挂钩:
ngOnInit() {
this.profileService
.getUserProfile()
.get()
.then( userProfileSnapshot => {
this.userProfile = userProfileSnapshot.data();
this.birthDate = userProfileSnapshot.data().birthDate;
});
}
同时,在您的个人资料服务中,方法“ getUserProfile”仍未定义,因为您只返回定义了类型但没有值的var:
getUserProfile(): firebase.firestore.DocumentReference {
return this.userProfile;
}
这是因为向this.userProfile分配值的方法是异步的:
constructor() {
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.currentUser = user;
this.userProfile = firebase.firestore().doc(`/userProfile/${user.uid}`);
}
});
因此,当您的生命周期挂钩已尝试利用userProfile时,甚至不会返回用户值。
已更新:
要解决此问题,您需要确保分配了诺言并进行了适当的“等待”:
在您的服务中,将userProfile和currentUser都定义为Promises:
public userProfile: Promise<any>;
public currentUser: Promise<any>;
在构造函数中执行
:this.currentUser = new Promise(async (resolve,reject)=>{
let user = await firebase.auth().onAuthStateChanged();
resolve(user)
})
this.userProfile = new Promise(async (resolve,reject)=>{
let user = await this.currentUser;
let userProfile = firebase.firestore().doc(`/userProfile/${user.uid}`);
})
现在,您的方法应该返回promise而不是未定义的var。请检查一下。我无法验证此代码,但我构建了一个类似于它的测试用例,它应该可以工作,但也请参见修复返回的类型:
getUserProfile(): Promise<any> {
return this.userProfile;
}