How can I delay the execution of "onAuthStateChanged" until "currentUser.updateProfile" has completed?

Currently facing an issue with registering users in my Vue app. When a user registers, I need to trigger the updateProfile function to add more user data. However, the problem arises when the onAuthStateChanged function in my main.js is executed before the updateProfile function, leading to undefined values for displayName and photoURL in Vuex. How can I ensure that the onAuthStateChanged waits for the updateProfile to finish?

In my Register.vue component, I have the following function:

register() {
      firebase
        .auth()
        .createUserWithEmailAndPassword(this.email, this.password)
        .then(user => {
          firebase
            .auth()
            .currentUser.updateProfile({
              displayName: this.displayName,
              photoURL: this.photoURL
            })
            .then(() => {
              db.collection("users")
                .doc(user.user.uid)
                .set({
                  email: this.email,
                  displayName: this.displayName,
                  realName: this.realName,
                  photoURL: this.photoURL
                })
                .then(() => {
                  console.log(user);
                  this.$router.replace("/");
                })
                .catch(err => {
                  this.errorMessage = err.message;
                });
            })
            .catch(err => {
              this.errorMessage = err.message;
            });
        })
        .catch(function(error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          if (errorCode == "auth/weak-password") {
            alert("The password is too weak.");
          } else {
            alert(errorMessage);
          }
          console.log(error);
        });
    }
  }

And in my main.js:

let app = "";

firebase.auth().onAuthStateChanged((user) => {
  store.dispatch("fetchUser", user);
  if (!app) {
    new Vue({
      router,
      store,
      render: (h) => h(App),
    }).$mount("#app");
  }
});

Answer №1

When you encounter the result of undefined, it's likely due to the fact that you are not returning the asynchronous functions within the register method.

Your current implementation looks like this

register() {
      firebase // This returns undefined as there is no return statement
        .auth()
        .createUserWithEmailAndPassword(this.email, this.password)
        .then(user => {
          firebase
            .auth()
            .currentUser.updateProfile({
              ....
            })
            .then(() => { // This also returns undefined as there is no return in the previous then block
              db.collection("users")
                .doc(user.user.uid)
                .set({
                  ......
                })
                .then(() => { // Again, this is undefined due to missing return in the previous then block
                 ....
                })
                .catch(err => {
                 ...
                });
            })
            .catch(err => {
              ....
            });
        })
        .catch(function(error) {
          ....
        });
    }
  }

To address this issue, consider the following approach

import { EventBus } from './eventBus.js';

register() {
  EventBus.$emit('user-registration-causes-auth-change', true) // Start by emitting this event to trigger a change in user authentication
// Alternatively, you can use `let self = this` to handle registration triggering auth state change
// (if using the alternative route, set this.isRegistrationTriggeringAuthStateChange = true;)
  return firebase
  .auth()
   ....
   .then(user => {
          return firebase
            .auth()
            .currentUser....
            .then(() => {
              return db.collection("users")
                ....
                .set({
                  ......
                })
                .then(() => {
                  EventBus.$emit('user-registration-causes-auth-change', false) // Set it to false after updating user profile
                   // If following the alternative path, set self.isRegistrationTriggeringAuthStateChange to false;
                })
       })
    })
}

eventBus.js

import Vue from 'vue';
export const EventBus = new Vue(); // Initialize an event bus here and export for use in other files

Main.js

import Vue from 'vue';
import { EventBus } from './eventBus.js';

let app
auth.onAuthStateChanged(async() => {
  if (!app) {
    app = new Vue({
      router,
      store,
      data: {
       isRegistrationTriggeringAuthStateChange: false; // Initialize as false to avoid interference with "fetchUser" dispatch
      },
      render: h => h(App)
    }).$mount('#app')
  }
  
  EventBus.$on('user-registration-causes-auth-change', (payload) => {
    app.isRegistrationTriggeringAuthStateChange = payload;
  })

  await Vue.$nextTick() // Wait for DOM update
  
  if (user && !app.isRegistrationTriggeringAuthStateChange) { // Conditional check here
    store.dispatch("fetchUser", user);
  }
})

EventBus.$off('user-registration-causes-auth-change', (payload) => { // Can be extracted into a handler
  app.isRegistrationTriggeringAuthStateChange = payload;
})

This is a raw code representation, feel free to refine it for better clarity.

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

Issue encountered when trying to insert an array in JavaScript into MongoDB using Mongoose

I am currently learning about node.js and mongodb. I attempted to insert a JavaScript array variable into mongodb using mongoose, but encountered an error. Upon running this code, I received the following error message: ValidationError: CastError: Cast t ...

The Lightgallery plugin is creating three duplicates of the slides

I am currently facing an issue with a gallery that loads images from an API and displays them using the lightgallery plugin. Upon implementing the lightbox in the correct location (view question here), I discovered that the plugin is generating three slid ...

Retrieve the value of a dynamically added or removed input field in JQuery using Javascript

Check out this informative article here I'm looking for a way to gather the values from all the text boxes and store them in an array within my JavaScript form. I attempted to enclose it in a form, but I'm struggling to retrieve the HTML ID beca ...

Trouble encountered in PHP: Generating a file from POST data and initiating download prompt for the user not functioning as intended

On my webpage, users fill out forms and input fields, which are then sent to a PHP page via Ajax and $_POST. The PHP file successfully writes the output to a txt file. However, I'm facing an issue trying to prompt the user to download the file on the ...

Tips for adjusting the size of grid tiles according to the dimensions of the window within a specific range

I am currently exploring how to replicate the effect found on this webpage: When the window size is adjusted, javascript dynamically resizes the grid tiles between 200 and 240px based on the optimal fit for the screen. Is there a ready-made JavaScript/jQ ...

Ways to obtain an attribute through random selection

Figuring out how to retrieve the type attribute from the first input element: document.getElementById('button').addEventListener('click', function() { var type = document.querySelectorAll('input')[0].type; document.getE ...

Activate JavaScript functions by pressing the enter key, allowing for various searches, AJAX requests, and DataTable displays to occur seamlessly without the need to refresh

I recently developed a web page that integrates an AWS API interface to interact with an RDS Aurora MySQL Serverless database. Users can input a SQL statement and click the Query button, which triggers an AJAX request, returns JSON data, and converts the d ...

Counting records in a nested ng-repeat using AngularJS

As a newcomer to AngularJS, I am facing an issue with a nested ng-repeat using a custom filter. I want to display the record count of Orders being shown, but when applying a product filter, it does not work as expected. For instance, if an order has no pro ...

Leveraging Vue's `:is` property for dynamically rendering components using a configuration object

I have created a confirmation popup Vue component with the following configuration object: { title: null, message: null, onConfirm: null, onDismiss: null, modal_class: null, icon: null, confirmBtnText: null, confirmBtnColor: null, compon ...

Mixing together an array of colors, experimenting with adding a touch of transparency

Here is my first question, diving right in. I recently created a canvas in HTML and followed a tutorial to generate random floating circles that interact with the mouse position......if you want to check it out, click here. The issue I'm facing now ...

Ways to merge two select options in a form

I'm attempting to merge the selections from two dropdown menus in a form into one variable before submitting the form. Here is an overview of my code: In new.html.erb (for RoR): <%= form_for :character, url: characters_path, method: :post do |f| ...

Passing props in Vue router results in the props being undefined

I am attempting to pass a props via the vue router using a router link that appears like this <router-link :to="{ name: 'product-details', params: { productId: 123 } }" class="product-sbb d-block"> Below are my routes { ...

What is the best way to store and retrieve data from the current webpage using HTML, CSS, and JavaScript?

Is there a way to persistently save the button created by the user even when the browser is refreshed? Here is an example code snippet: function create(){ const a = document.createElement("button") document.body.appendChild(a) const b = documen ...

Harnessing the power of two-way data binding in VueJS

I am looking to utilize Vue's two-way data binding to dynamically update the values of amount and total. The price of a given product is fixed. When users modify the amount, the total = amount * total will be automatically calculated. Similarly, users ...

Rendering deeply nested data in a Vue table

I am currently in the process of updating some older code, transitioning to Vue as a replacement. Everything has been going smoothly except for one specific table that is templated using handlebars. With handlebars and nested {{each}} loops, I can easily ...

The error message TS2304 is indicating that the name 'Set' cannot be found in electron-builder

I am trying to utilize the AppUpdater feature in electron-builder for my Electron Application. Upon importing the updater in my main.ts file: import { autoUpdater } from "electron-updater" An error is triggered when running the application: node_module ...

What is the best way to update a local variable in JavaScript using Ajax requests?

function validate_authentication(){ var is_authenticated = false; $.ajax({ type: "POST", url: "/account/islogin/", data: "", async: "false", success: function(data) { if (data == "null") { ...

Hide the div when hovering occurs

I need a way to hide the 'sample' div when hovering over it and then show it again when the mouse moves away $('.secmenu').hover(function() { $('.sample').css('opacity', '0'); if ($('.secmenu&a ...

How can I prevent clearQueue() from removing future queues?

In my code, I have a button that triggers the showing of a div in 500ms when clicked. After the div is shown, a shake class is added to it after another 500ms. The shake class is then removed after 2 seconds using the delay function. However, if the user c ...

Utilize Google Maps geocoding functionality to pinpoint a location and then

I've encountered this strange phenomenon, but first let's take a look at the code: HTML <div ng-app='maptesting'> <div ng-controller="MapCtrl"> <div id="map_canvas" ui-map="myMap" style ...