`Firebase User Instance and Custom Firestore Document`

Recently, I posted a question regarding Google Firebase Angular Firestore switchMap and encountered some issues. The question can be found here.

After exploring AngularFireAuth, I learned that it is used to create a User object with fixed values, requiring custom values to be added through Google Firestore.

I have successfully created an entry in Firestore and defined a User Model as follows:

export interface User {
  uid: string;
  email: string;
  displayName?: string;
  role: string;
  thursdayCampaign: Boolean;
  menagerieCoast: Boolean;
}

The code snippet below should retrieve the uid from the AngularFireAuth User object and then utilize switchMap to interact with the Firebase store. However, a problem arises when my updateUserData function attempts to update the AngularFireAuth User Object with additional data, causing an error due to incompatible field values.

At this point, I am puzzled as to why my reference is not redirecting properly. Do I need to include a call to this.user$ somewhere in the code?

In hopes of better articulating my issue compared to my prior post, please find the relevant code below:

import { Injectable } from "@angular/core";
import { Router } from '@angular/router';

import { auth } from 'firebase/app';
import {
    AngularFirestore,
    AngularFirestoreDocument
} from '@angular/fire/firestore'

import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { User } from './user1.model';

import * as firebase from 'firebase';
import { AngularFireAuth } from '@angular/fire/auth';



@Injectable({
  providedIn: 'root'
})
export class AuthService {

  user$: Observable<User[]>;

  constructor(private afAuth: AngularFireAuth,
              private afs: AngularFirestore,
              private router: Router) {

        //This is how we're getting into the firestoreDB        
        this.user$ = this.afAuth.authState.pipe(
          switchMap(user => {
            if (user){
              return this.afs.doc<User>(`/users/${user.uid}`).valueChanges();
            } else {
                return of(null)
            }
          })
        )
              } //end constructor

  public updateUserData(user){
    const userRef: AngularFirestoreDocument<User> = this.afs.doc(`users/${user.uid}`)
    
    const data: User = {
      uid: user.uid,
      email: user.email,
      displayName: user.displayName,
      role: user.role,
      thursdayCampaign: user.thursdayCampaign,
      menagerieCoast: user.menagerieCoast
    }
    
     userRef.set(data, { merge: true})
  }


  async emailSignin(value){
    const credential = await this.afAuth.signInWithEmailAndPassword(value.email, value.password)
    return this.updateUserData(credential.user), 
    this.router.navigate(['/home'])
  }


  async googleSignin(){
    const provider = new auth.GoogleAuthProvider();
    const credential = await this.afAuth.signInWithPopup(provider);
    return this.updateUserData(credential.user)
  }

Error message received when calling emailSignin:

ERROR Error: Uncaught (in promise): FirebaseError: [code=invalid-argument]: Function DocumentReference.set() called with invalid data. Unsupported field value: undefined (found in field role) FirebaseError: Function DocumentReference.set() called with invalid data. Unsupported field value: undefined (found in field role)

Answer №1

If you only call the updateUserData function during authentication, you can safely exclude the role, thursdayCampaign, and menagerieCoast from the data payload.

By using { merge: true}, only the data present in the payload will be updated without affecting the entire document. This ensures that your existing fields remain unchanged and prevents any errors from occurring.

The purpose of the updateUserData method is crucial during a new user's sign-in process as it manages the transfer of data from Firebase authentication to Firestore database, creating a unique UID in the database. For future updates to user data, consider implementing a separate method for this task.

NOTE: Information regarding this topic can also be found in the video tutorial shared in the comments section. You may refer to the link for more details.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Best practices for managing backend errors with Next.js 14

Currently, I am developing a project in Next.js 14 and I have set up my API requests using fetch within a handler.tsx file as shown below: async function getPositions() { const response = await fetch( process.env.BASE_API_URL + "/positions?enabl ...

Angular: finding out if Observable or BehaviorSubject has undergone any important modifications

I am facing an issue with my user object in a membership service. I need to ensure that my services are updated only when there are relevant changes in the user object. To determine if there are relevant changes in the user object, I compare it with the ...

Karma is indicating an issue with TypeError: Unable to access the property 'textContent' because it is undefined

I am currently working on a basic unit test and facing some challenges. Despite trying multiple approaches, I am unable to resolve the error that is causing all tests except the first one to fail. Below is the content of the spec file: fdescribe("New Tes ...

What could be the rationale behind the optional chaining operator not being fully compatible with a union of classes in TypeScript?

Imagine I have a combination of classes: type X = ClassA | ClassB | ClassC; Both ClassA and ClassC have a shared method called methodY. Why is it that I can't simply use the optional chaining operator to call for methodY? class ClassA { methodY ...

ParcelJS takes a unique approach by not bundling imported JavaScript libraries

My NodeJS app, which is a Cloudflare Worker, seems to be having trouble with bundling the 'ping-monitor' dependency. In my main typescript file (index.ts), I import the handler module and the first line reads: const Monitor = import('ping-m ...

The module '@angular/http/src/static_response' or its corresponding type declarations could not be located

I'm encountering an issue in my Angular v12 project where I receive the error message Cannot find module '@angular/http/src/static_response' or its corresponding type declarations when I attempt to use the import statement in my code: import ...

Step-by-step guide to initializing a project using React with Typescript and a functional server-side script

I am working on a project that involves a React Typescript app (created using Create React App). In this project, I need to have an executable script that can run alongside the React app. Both the app and the script are intended to only run on local machin ...

Ways to steer clear of utilizing subscriptions and BehaviorSubject.value through a declarative method within rxjs

As I refactor my Angular application, my goal is to eliminate all subscriptions and rely solely on the async pipe provided by Angular for a declarative approach instead of an imperative one. I encounter difficulties implementing a declarative approach whe ...

Enhancing component and view functionality in Angular

Recently, I started working on Angular 11 and encountered a simple yet challenging question. Despite my best efforts, I have been unable to find a suitable answer. In an attempt to utilize Object-Oriented Programming (OOP) concepts within Angular, I create ...

The designated route, "**", is for displaying a page that cannot be found

Utilizing routing in Angular 2 with TypeScript has been a beneficial choice for my project. In the main index.html, I included <base href=""> instead of <base href="/"> to accommodate a specialized route requirement. This setup has been effecti ...

Trying out cellRenderer in Angular's Ag Grid with Jest to validate values

I am facing an issue where I need to test the actual values displayed in a column of an Ag Grid table. These values are formatted using a cellRenderer based on specific conditions. In my Jest test, I have experimented with various approaches: Using fixtu ...

Loading large amounts of data efficiently with Angular and Firebase

Currently, I am utilizing AngularJS in conjunction with Firebase. Objective: My aim is to showcase all the information stored within my Firebase database (which consists of a fixed number of approximately 1600 items). Challenge: The issue at hand is that ...

How to retain the side menu icon in Ionic 2 even after navigating using navCtrl push

Whenever I navigate to a new page using navCtrl.push, the sidemenu icon (hamburger) disappears and is replaced by a back button instead of coexisting with it. What I am aiming for is to retain the sidemenu icon by positioning it on the right side of the i ...

Error in Angular multiselect dropdown: Unable to retrieve the length of undefined property

counter: number = 0; getDatatypes(){ if(this.counter == 0) { if(this.appId != 0) { if(undefined != this.datatypes && this.datatypes.length) for (let i = 0; i < this.datatypes.length; i++) { this.ap ...

Can you explain the mechanics behind the functionalities of @angular and @type dependencies?

This inquiry may have been raised before, but I couldn't uncover all the solutions. If that's the case, my apologies. I have a good grasp on how package.json and dependencies / dev-dependencies function in Node applications. Currently delving i ...

Having trouble transferring captured images to Firebase storage

I am currently working on creating a small Ionic 2 application that is capable of capturing images using the camera and then uploading those images to Firebase storage. Additionally, I aim to store the URLs of the captured images in the Firebase database. ...

Encountering an issue when retrieving the value from a template-driven Angular form

Encountering an issue in the register function regarding storing the form control value. When using "let firstname", "let lastname", and "let email", I am receiving the error [tslint] Identifier 'firstName' is never reassigned; use 'const&a ...

Choosing a value with an Ionic checkbox

Here's the coding template I'm working on: <ion-list > <ion-item> <ion-label>This month</ion-label> <ion-checkbox checked=true></ion-checkbox> </ion-item> ...

[Protractor][Scroll] I need assistance with scrolling my webpage using a while loop. Could someone please help me troubleshoot the code?

When this function is called, it initiates scrolling and then pauses the browser for a 2-second period. scrollToElement(webElement: any) { browser.executeScript('window.scrollTo(0,400);').then(()=>{ console.log("sleepin ...

Conceal certain components when a user is authenticated

Below is the content of my app.component.html: <nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class='container'> <ul class="nav navbar-nav"> <li class='nav-item'> <a clas ...