I Got a service in Angular that gets User Data from firestore. The relevant service code is as follows:
userType:string = ''
async getProfileType(): Promise<string> {
const userUID = await this.getUserUID();
const getUserType = () => {
this.af
.collection('users')
.doc(userUID)
.valueChanges()
.subscribe((doc: any) => {
console.log(doc.userType);
this.userType = doc.userType;
});
return this.userType;
};
return getUserType();
}
When I try to invoke it in the component by injecting it and calling the function in the ngOnInit method I get the following error:
ERROR TypeError: Cannot read properties of undefined (reading 'userType')
And when I invoke the function from the service manually it returns the data fine, but I'm not sure why it can't do the same thing when invoked on the ngOnInit method.
I've tried making ngOnInit async and use await on the getProfileType function but that didn't seem to make a difference.
The Component TypeScript is as follows:
import { Component, OnInit } from '@angular/core';
import { AngularFirestore } from '@angular/fire/compat/firestore';
import { UserInfoService } from '../services/user-info/user-info.service';
@Component({
selector: 'app-edit-profiles',
templateUrl: './edit-profiles.component.html',
styleUrls: ['./edit-profiles.component.scss'],
})
export class EditProfilesComponent implements OnInit {
constructor(public userInfo: UserInfoService, private af: AngularFirestore) {}
async ngOnInit() {
this.userInfo.getProfileType();
}
The Component HTML is as follows:
<div *ngIf="userInfo.userType === 'user'">
You're a User
</div>
<div *ngIf="userInfo.userType === 'project'">
You're a Project
</div>
<button mat-flat-button (click)="userInfo.getProfileType()">Get Profile Type</button>
Any help or direction is appreciated, cheers!
CodePudding user response:
Your getProfileType
method claims to be returning a Promise<string>
, but it's actually just returning a string
that hasn't been initialize yet as you're never awaiting the database result.
async getProfileType(): Promise<string> {
I'd recommend returning an Observable<string>
, since the profile type may change:
getProfileType(): Observable<string> {
const userUID = await this.getUserUID();
return this.af
.collection('users')
.doc(userUID)
.valueChanges()
.pipe(map((doc: any) => {
return doc.userType;
}));
}
Alternatively, you can stick to the Promise
approach, but then return just one document with take(1)
or first()
:
getProfileType(): Observable<string> {
const userUID = await this.getUserUID();
return this.af
.collection('users')
.doc(userUID)
.valueChanges()
.pipe(take(1))
.pipe((doc: any) => {
return doc.userType;
});
}