Angular 当身份验证状态更改时,在map操作符内调用一个方法

Angular 当身份验证状态更改时,在map操作符内调用一个方法,angular,angularfire2,Angular,Angularfire2,我正在用Angular 8和Angular 8开发一个web应用程序 我正在尝试实现Firebase身份验证以登录用户,然后在Firestore中读取其数据。最后,使用本地BehaviorSubject保存此数据 import {User} from 'firebase'; export interface FirebaseUser { readonly uid: string; readonly email: string; readonly emailVerified: boo

我正在用Angular 8和Angular 8开发一个web应用程序

我正在尝试实现Firebase身份验证以登录用户,然后在Firestore中读取其数据。最后,使用本地
BehaviorSubject
保存此数据

import {User} from 'firebase';

export interface FirebaseUser {
  readonly uid: string;
  readonly email: string;
  readonly emailVerified: boolean;
}

export interface IUser {
  id?: string;
  email: string;
  name: string;
  gender: string;
}

@Injectable()
export class AuthService {

  // To have the user's auth data from Firebase Authentication.
  private bsCurrentUserAuth: BehaviorSubject<FirebaseUser> = new BehaviorSubject<FirebaseUser>(null);
  readonly currentUserAuth$: Observable<FirebaseUser> = this.bsCurrentUserAuth.asObservable();

  // To have the user's document data.
  private bsCurrentUser: BehaviorSubject<IUser> = new BehaviorSubject<IUser>(null);
  readonly currentUser$: Observable<IUser> = this.bsCurrentUser.asObservable();

  private user$: Observable<IUser>;

  constructor(
    private afAuth: AngularFireAuth,
    private afs: AngularFirestore,
  ) {
    // Subscribe to the auth state, then get firestore user document || null
    this.user$ = this.afAuth.authState.pipe(
      switchMap(user => {
        // Logged in
        if (user) {
          return this.afs.doc<IUser>(`${COLLECTIONS.USERS}/${user.uid}`).snapshotChanges()
            .pipe(
              map(changes => {
                const data = changes.payload.data() as IUser;
                const id = changes.payload.id;
                const docData = {id, ...data};
                this.saveUser(user, docData); // This is not being called.
                return docData;
              }));
        } else {
          // Logged out
          this.clearAll();
          return of(null);
        }
      })
    );
  }

  // This is not being called.
  private saveUser(user: User, userDoc: IUser) {
    console.log('saveUser');
    this.bsCurrentUserAuth.next(user);
    this.bsCurrentUser.next(userDoc);
  }

  private clearAll() {
    this.bsCurrentUserAuth.next(null);
    this.bsCurrentUser.next(null);
  }

  login(email: string, password: string): Promise<UserCredential> {
    return this.afAuth.auth.signInWithEmailAndPassword(email, password);
  }

}
从“firebase”导入{User};
导出接口FirebaseUser{
只读uid:string;
只读电子邮件:字符串;
只读电子邮件验证:布尔;
}
导出接口IUser{
id?:字符串;
电子邮件:字符串;
名称:字符串;
性别:弦;
}
@可注射()
导出类身份验证服务{
//从Firebase身份验证获取用户的身份验证数据。
private bsCurrentUserAuth:BehaviorSubject=新的BehaviorSubject(null);
readonly currentUserAuth$:Observable=this.bsCurrentUserAuth.asObservable();
//获取用户的文档数据。
private bsCurrentUser:BehaviorSubject=新的BehaviorSubject(null);
只读currentUser$:Observable=this.bsCurrentUser.asObservable();
私有用户$:可观察;
建造师(
私人afAuth:AngularFireAuth,
私人afs:AngularFirestore,
) {
//订阅身份验证状态,然后获取firestore用户文档| | null
this.user$=this.afAuth.authState.pipe(
开关映射(用户=>{
//登录
如果(用户){
返回此.afs.doc(`${COLLECTIONS.USERS}/${user.uid}`)。快照更改()
.烟斗(
映射(更改=>{
const data=将.payload.data()更改为IUser;
const id=changes.payload.id;
const docData={id,…data};
this.saveUser(user,docData);//未调用此函数。
返回文档数据;
}));
}否则{
//注销
这个;
返回(空);
}
})
);
}
//这是没有被称为。
私有存储用户(用户:用户,用户文档:IUser){
log('saveUser');
this.bsCurrentUserAuth.next(用户);
this.bsCurrentUser.next(userDoc);
}
私有clearAll(){
this.bsCurrentUserAuth.next(null);
this.bsCurrentUser.next(空);
}
登录(电子邮件:string,密码:string):承诺{
使用email和password(电子邮件,密码)返回此.afAuth.auth.Signin;
}
}
现在,用户可以登录,但是我想保存在
行为子对象中的数据不在那里,因为出于某种原因,
saveUser()
方法没有被调用

这个想法是:

  • 登录
  • BehaviorSubject
    中保存来自Firebase身份验证的用户身份验证数据
  • 将用户的文档数据保存在
    行为主题中

  • 我的目标是在两个
    行为主题
    中提供这些数据,我看不出您实际订阅用户$observable的位置。看看这个,假设您有正确的导入并订阅user$,它应该可以正常工作。登录和获取用户状态是不耦合的,所以我猜您只是缺少订阅位

    import {User} from 'firebase';
    
    export interface FirebaseUser {
      readonly uid: string;
      readonly email: string;
      readonly emailVerified: boolean;
    }
    
    export interface IUser {
      id?: string;
      email: string;
      name: string;
      gender: string;
    }
    
    @Injectable()
    export class AuthService {
    
      // To have the user's auth data from Firebase Authentication.
      private bsCurrentUserAuth: BehaviorSubject<FirebaseUser> = new BehaviorSubject<FirebaseUser>(null);
      readonly currentUserAuth$: Observable<FirebaseUser> = this.bsCurrentUserAuth.asObservable();
    
      // To have the user's document data.
      private bsCurrentUser: BehaviorSubject<IUser> = new BehaviorSubject<IUser>(null);
      readonly currentUser$: Observable<IUser> = this.bsCurrentUser.asObservable();
    
      private user$: Observable<IUser>;
    
      constructor(
        private afAuth: AngularFireAuth,
        private afs: AngularFirestore,
      ) {
        // Subscribe to the auth state, then get firestore user document || null
        this.user$ = this.afAuth.authState.pipe(
          switchMap(user => {
            // Logged in
            if (user) {
              return this.afs.doc<IUser>(`${COLLECTIONS.USERS}/${user.uid}`).snapshotChanges()
                .pipe(
                  map(changes => {
                    const data = changes.payload.data() as IUser;
                    const id = changes.payload.id;
                    const docData = {id, ...data};
                    this.saveUser(user, docData); // This is not being called.
                    return docData;
                  }));
            } else {
              // Logged out
              this.clearAll();
              return of(null);
            }
          })
        );
      }
    
      // This is not being called.
      private saveUser(user: User, userDoc: IUser) {
        console.log('saveUser');
        this.bsCurrentUserAuth.next(user);
        this.bsCurrentUser.next(userDoc);
      }
    
      private clearAll() {
        this.bsCurrentUserAuth.next(null);
        this.bsCurrentUser.next(null);
      }
    
      login(email: string, password: string): Promise<UserCredential> {
        return this.afAuth.auth.signInWithEmailAndPassword(email, password);
      }
    
    }
    
    import {User} from 'firebase';
    
    export interface FirebaseUser {
      readonly uid: string;
      readonly email: string;
      readonly emailVerified: boolean;
    }
    
    export interface IUser {
      id?: string;
      email: string;
      name: string;
      gender: string;
    }
    
    @Injectable()
    export class AuthService {
    
      // To have the user's auth data from Firebase Authentication.
      private bsCurrentUserAuth: BehaviorSubject<FirebaseUser> = new BehaviorSubject<FirebaseUser>(null);
      readonly currentUserAuth$: Observable<FirebaseUser> = this.bsCurrentUserAuth.asObservable();
    
      // To have the user's document data.
      private bsCurrentUser: BehaviorSubject<IUser> = new BehaviorSubject<IUser>(null);
      readonly currentUser$: Observable<IUser> = this.bsCurrentUser.asObservable();
    
      private user$: Observable<IUser>;
    
      constructor(
        private afAuth: AngularFireAuth,
        private afs: AngularFirestore,
      ) {
        // Subscribe to the auth state, then get firestore user document || null
        this.user$ = this.afAuth.authState.pipe(
          switchMap(user => {
            // Logged in
            if (user) {
              return this.afs.doc<IUser>(`${COLLECTIONS.USERS}/${user.uid}`).snapshotChanges()
                .pipe(
                  map(changes => {
                    const data = changes.payload.data() as IUser;
                    const id = changes.payload.id;
                    const docData = {id, ...data};
                    this.saveUser(user, docData); // This is not being called.
                    return docData;
                  }));
            } else {
              // Logged out
              this.clearAll();
              return of(null);
            }
          })
        ).subscribe();
    //you need to actually subscribe to the user state be sure to also unsubscribe when this is destroyed if not a singleton service
      }
    
      // This is not being called.
      private saveUser(user: User, userDoc: IUser) {
        console.log('saveUser');
        this.bsCurrentUserAuth.next(user);
        this.bsCurrentUser.next(userDoc);
      }
    
      private clearAll() {
        this.bsCurrentUserAuth.next(null);
        this.bsCurrentUser.next(null);
      }
    
      login(email: string, password: string): Promise<UserCredential> {
        return this.afAuth.auth.signInWithEmailAndPassword(email, password);
      }
    
    }
    
    从“firebase”导入{User};
    导出接口FirebaseUser{
    只读uid:string;
    只读电子邮件:字符串;
    只读电子邮件验证:布尔;
    }
    导出接口IUser{
    id?:字符串;
    电子邮件:字符串;
    名称:字符串;
    性别:弦;
    }
    @可注射()
    导出类身份验证服务{
    //从Firebase身份验证获取用户的身份验证数据。
    private bsCurrentUserAuth:BehaviorSubject=新的BehaviorSubject(null);
    readonly currentUserAuth$:Observable=this.bsCurrentUserAuth.asObservable();
    //获取用户的文档数据。
    private bsCurrentUser:BehaviorSubject=新的BehaviorSubject(null);
    只读currentUser$:Observable=this.bsCurrentUser.asObservable();
    私有用户$:可观察;
    建造师(
    私人afAuth:AngularFireAuth,
    私人afs:AngularFirestore,
    ) {
    //订阅身份验证状态,然后获取firestore用户文档| | null
    this.user$=this.afAuth.authState.pipe(
    开关映射(用户=>{
    //登录
    如果(用户){
    返回此.afs.doc(`${COLLECTIONS.USERS}/${user.uid}`)。快照更改()
    .烟斗(
    映射(更改=>{
    const data=将.payload.data()更改为IUser;
    const id=changes.payload.id;
    const docData={id,…data};
    this.saveUser(user,docData);//未调用此函数。
    返回文档数据;
    }));
    }否则{
    //注销
    这个;
    返回(空);
    }
    })
    ).subscribe();
    //您需要实际订阅用户状态。如果不是单例服务,请确保在用户状态被破坏时也取消订阅
    }
    //这是没有被称为。
    私有存储用户(用户:用户,用户文档:IUser){
    log('saveUser');
    this.bsCurrentUserAuth.next(用户);
    this.bsCurrentUser.next(userDoc);
    }
    私有clearAll(){
    this.bsCurrentUserAuth.next(null);
    this.bsCurrentUser.next(空);
    }
    登录(电子邮件:string,密码:string):承诺{
    使用email和password(电子邮件,密码)返回此.afAuth.auth.Signin;
    }
    }
    
    我为什么需要订阅?我认为te文档的读取将通过返回
    this.afs.doc(…)
    完成。如果我不订阅,保存在Observable中的只是文档的引用?我不明白逻辑…在你订阅之前,你所做的就是创建一个可观察的。可以在其他地方订阅。但除非你真的订阅了它,否则它不会执行。这个.afs.doc(…)永远不会发生,因为observable没有任何东西可以观察到它。谢谢你的解释。我注意到我的IDE在
    中给了我一个错误。user$
    说“Type'Subscription'缺少Type'obbservable'中的以下属性:\ isScalar、source、operator、lift,还有6个。”。知道为什么会出现这种错误吗?