1

I tried building an CMS app in Angular 5 using Firebase but getting an error in switch map and User interface

  1. switchmap() unresolvable function or method.

  2. Initializer type uid, email etc. can't be assigned to variable type User

af.service.ts

import { Injectable } from '@angular/core';
import {AngularFireAuth} from '@angular/fire/auth';
import {Observable, of} from 'rxjs';
import * as firebase from 'firebase/app';
import {AngularFirestore, AngularFirestoreDocument} from '@angular/fire/firestore';
import { switchMap } from 'rxjs/operators';
import { User } from './user';

@Injectable({
  providedIn: 'root'
})
export class AfService {
  user$: Observable<User>;
  constructor( public afAuth: AngularFireAuth,
               public afs: AngularFirestore) {
    this.user$ = afAuth.authState.switchMap(user => {
      if (user) {
        return this.afs.doc<User>(`users/$(user.uid)`).valueChanges();
      } else {
        return of(null);
      }
    });
  }
    loginWithGoogle() {
      const provider = new firebase.auth.GoogleAuthProvider();
      this.afAuth.auth.signInWithPopup(provider).then((credential) => {
        this.updateUser(credential.user);
      });
    }
  updateUser(user) {
      const userRef: AngularFirestoreDocument<any> = this.afs.doc(`users/$(user.uid)`);
      const data: User = {
        uid: User.id,
        email: User.email,
        roles: {
          subscriber: true,
          admin: false
        }
      }
      return userRef.set(data, {merge: true});
  }
    logout() {
      this.afAuth.auth.signOut();
    }
}

user.ts

export interface User {
  uid: string;
  email: string;
  displayName: string;
  roles: Roles;
}

export interface Roles {
  subscriber?: boolean;
  admin?: boolean;
}
LazyOne
  • 158,824
  • 45
  • 388
  • 391
HelloStack
  • 13
  • 4
  • 1
    Which version of AngularFire are you using? It may be that you need to use the new syntax using `pipe`. – Will Alexander Aug 15 '19 at 14:34
  • Also, your attempted instantiation of a `User` in `updateUser` looks wrong. I think you mean to use `userRef` and not `User` inside the object, plus it's missing a `displayName` member – Will Alexander Aug 15 '19 at 14:37
  • @WillAlexander I'm still getting error while using userRef ,and I think that it's not important to call all the member like displayName(correct me if I'm wrong) – HelloStack Aug 15 '19 at 17:28
  • 1
    to answer your latest question, if you have declared displayName as a required prop, you need to add it to your payload, if not, make it optional. – AT82 Aug 15 '19 at 17:29
  • If your object doesn't contain all of the necessary fields, it doesn't implement the interface correctly. – Will Alexander Aug 15 '19 at 17:34
  • @AJT_82 Thanks it helped a little! But I'm still getting error 'User' only refers to a type,but is being used as a value here. – HelloStack Aug 15 '19 at 18:19
  • @HelloStack, did you check my answer? – AT82 Aug 15 '19 at 18:20
  • @AJT_82: Yes I marked displayName as optional field. – HelloStack Aug 15 '19 at 18:25
  • @HelloStack But did you look at my answer, below this comment section? You have other issues too. – AT82 Aug 15 '19 at 18:26
  • @AJT_82 Now getting promise rejection at RunTime Unhandled Promise rejection: Missing or insufficient permissions. ; Zone: ; Task: Promise.then ; Value: FirebaseError: Missing or insufficient permissions. at new FirestoreError (http://localhost:4200/vendor.js:107908:28) – HelloStack Aug 15 '19 at 18:41
  • 1
    @AJT_82 Thanks!!!! It worked:) – HelloStack Aug 15 '19 at 18:48

1 Answers1

2

I see some issues, you are importing switchMap in a way that it should be used inside pipe. Also you have typos (?): $(user.uid) should be ${user.uid}. Also you are passing user to your updateUser function, but you are using the type User in your payload. Also, you need to include displayName in your payload, since you have made it required. Sooooo....

Change the round brackets to curly on both places (updateUser() and authState):

return this.afs.doc<User>(`users/${user.uid}`).valueChanges();

Then set switchMap inside pipe():

this.user$ = this.afAuth.authState.pipe(
    switchMap(user => {
        if (user) {
            return this.afs.doc<User>(`users/${user.uid}`).valueChanges();
        } else {
            return of(null);
        }
    })
);

Change the payload for the updateUser:

const data: User = {
  uid: user.uid, // should be uid, not id!
  email: user.email,
  displayName: user.displayName
  roles: <Roles>{
    subscriber: true,
    admin: false
  }
}
AT82
  • 71,416
  • 24
  • 140
  • 167