Save user to realtime database not working

Viewed 72

UPDATED

I have a function where it saves the user's data to my database and navigates to the dashboard, but it's not working. Once it sends the message that it has collected the data, it refreshes and doesn't save the user's info. I didn't get an error when I checked the console. I have provided my code below:

// Initialize Firebase
firebase.initializeApp(firebaseConfig);
  
// Initialize variables
const auth = firebase.auth()
const database = firebase.database()


//Updated Save Data Function
function handleNewStudioFormSubmit() { // renamed from newStudio
  // don't use alert - it blocks the thread
  console.log('debug: retrieving data... please wait')
  
  // Get data
  studioName = document.getElementById("studioName").value;
  email = document.getElementById("email").value;
  password =  document.getElementById("password").value;
  firstName = document.getElementById("firstName").value;
  lastName = document.getElementById("lastName").value;
  phoneNumber = document.getElementById("phoneNumber").value;

  console.log({ studioName, firstName, email }); // note added braces here
  
  // Validate input fields
  if (
    !validate_email(email) || 
    !validate_password(password)
    ) {
    // TODO: replace this alert with updating the form with an error message
    alert('Error with email or password')
    return false // cancel submission
  }

  if (
    !validate_field(firstName) ||
    !validate_field(lastName) ||
    !validate_field(phoneNumber) ||
    !validate_field(studioName)
    ) {
    // TODO: replace this alert with updating the form with an error message
    alert('One or More Extra Fields is Outta Line!!')
    return false // cancel submission
  };

  return createStudioThenOpenDashboard({
    studioName,
    firstName,
    lastName,
    email,
    password,
    phoneNumber
  })
    .catch((err) => {
      console.error('failed to create studio: ', err);
      alert('Failed to create studio. Cause: ' + err.message);
    });
}

// ⇊ permits using await
async function createStudioThenOpenDashboard(data) {
  /* ... */

  const { email, password, firstName, lastName, phoneNumber } = data;

  // creates the user, and waits for it to finish being created
  const user = await auth.createUserWithEmailAndPassword(email, password);

  // writes data to the database, and waits for it to complete
  await firebase.database()
    .ref('/studiopick/studio/users/' + studioName) // <-- note fixed path
    .set({
      studioName : studioName,
      firstName : firstName,
      lastName : lastName,
      email : email,
      phoneNumber : phoneNumber,
      uid: user.uid
      // NEVER store passwords in plain text, even in testing
    });

  // once the above tasks succeed, navigate to the dashboard.
  window.location.href = "studiodash.html?id=" + uid
}

// Validate Functions
function validate_email(email) {
  expression = /^[^@]+@\w+(\.\w+)+\w$/
  if (expression.test(email) == true) {
    // Email is good
    return true
  } else {
    // Email is not good
    return false
  }
}

function validate_password(password) {
  // Firebase only accepts lengths greater than 6
  if (password < 6) {
    return false
  } else {
    return true
  }
}

function validate_field(field) {
  if (field == null) {
    return false
  }

  if (field.length <= 0) {
    return false
  } else {
    return true
  }
}

HTML

<!DOCTYPE html>
<html>
    <head>
        <!---Required meta tags--->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="CSS/studiosignup.css">
        <script>"https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"</script>
        <!---Required meta tags--->
    
        <!---Like Button JavaScript--->
        <script src="https://kit.fontawesome.com/f6dcf461c1.js" crossorigin="anonymous"></script>
        <!---Like Button JavaScript--->
    
        <!---Bootstrap CSS--->
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
        crossorigin="anonymous">
        <!---Bootstrap CSS--->
        
        <title>StudioPick</title>
        
    </head>
    <body>
        <header>
            <nav class="navbar navbar-expand-lg navbar-light">
                <div class="container-fluid">
                <a style="font-size: 45px; color: #A388E7;" class="navbar-brand" href="#"><strong>StudioPick</a>
                    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                    </button>
                    <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
                        <li class="nav-item">
                        <a class="nav-link active" aria-curresnt="page" href="index.html">Home</a>
                        </li>
                        <li class="nav-item">
                        <a class="nav-link" href="signupprofileselect.html">Sign Up</a>
                        </li>
                        <li class="nav-item2">
                        <a class="nav-link" href="login.html">Login</a>
                        </li>
                    </ul>
                    </div>
                </div>
            </nav>
        </header>
        <form class="container py-5 h-100" id="contactForm">
            <div class="row d-flex justify-content-center align-items-center h-100">
                <div class="col-12 col-md-8 col-lg-6 col-xl-5">
                    <div class="card-dark text-white" style="border-radius: 1rem;">
                        <div class="card-body p-5 text-center" id="signUp">
                            <div class="mb-md-5 mt-md-4 pb-5">
                                <h2 class="text-black fw-bold mb-2 text-uppercase">Sign Up</h2>
                                <p class="text-black mb-5">Please enter your email and password!</p>

                                <div class="text-black form-outline form-white mb-4">
                                    <label class="form-label" for="firstName">First Name*</label>
                                    <input type="text" id="firstName" class="form-control form-control-lg">
                                </div>
                                <div class="text-black form-outline form-white mb-4">
                                    <label class="form-label" for="lastName">Last Name*</label>
                                    <input type="text" id="lastName" class="form-control form-control-lg">
                                </div>
                                <div class="text-black form-outline form-white mb-4">
                                    <label class="form-label" for="email">Email*</label>
                                    <input type="email" id="email" class="form-control form-control-lg">
                                </div>
                                <div class="text-black form-outline form-white mb-4">
                                    <label class="form-label" for="phoneNumber">Phone Number*</label>
                                    <input type="text" id="phoneNumber" class="form-control form-control-lg">
                                </div>
                                <div class="text-black form-outline form-white mb-4">
                                    <label class="form-label" for="userName">Studio Name*</label>
                                    <input type="text" id="studioName" class="form-control form-control-lg">
                                </div>
                                <div class="text-black form-outline form-white mb-4">
                                    <label class="form-label" for="password">Enter a Password*</label>
                                    <input type="password" id="password" class="form-control form-control-lg">
                                </div>

                                <button class="text-black btn px-5" id="subbtn" type="submit" onclick="newStudio()"><strong>Sign Up</strong></button>
                                <button id="reg-btn" class="currentuser">Already Have An Account? Sign In</button>
                                <div class="socials">
                                    <a href="#!" class="text-black"><i class="fab fa-facebook-f fa-lg"></i></a>
                                    <a href="#!" class="text-black"><i class="fab fa-twitter fa-lg mx-4 px-2"></i></a>
                                    <a href="#!" class="text-black"><i class="fab fa-google fa-lg"></i></a>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </form>

        <footer class="my-5 pt-5 text-muted text-center text-small">
            <p class="mb-1">© 2022 StudioPick.</p>
            <ul class="list-inline">
              <li class="list-inline-item"><a href="#">Privacy</a></li>
              <li class="list-inline-item"><a href="#">Terms</a></li>
              <li class="list-inline-item"><a href="#">Support</a></li>
            </ul>
          </footer>
    <!-- The core Firebase JS SDK is always required and must be listed first -->
    <script src="https://www.gstatic.com/firebasejs/8.6.8/firebase-app.js"></script>

    <!-- TODO: Add SDKs for Firebase products that you want to use
        https://firebase.google.com/docs/web/setup#available-libraries -->
    <script src="https://www.gstatic.com/firebasejs/8.6.8/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.6.8/firebase-database.js"></script>

    <!-- Our script must be loaded after firebase references -->
    <script src="Javascript/studiosignup.js"></script>
    
    <!----More Bootstrap--->
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
    <!----More Bootstrap--->
</body>
</html>

1 Answers

In short, you are firing off asynchronous tasks, without waiting for them to finish. Additionally, by using alert() throughout your function, you are also blocking the thread which leads to confusing behaviour - such as asynchronous tasks never being executed properly.

Take a look at these parts of your code:

function newStudio() {
  /* ... */
  
  // ⇊ this is asynchronous, you should wait for it to finish
  auth.createUserWithEmailAndPassword(email, password)
    .then(function() {
      // Declare user variable
      var user = auth.currentUser
    })
    .catch(function(error) {
      // Firebase will use this to alert of its errors
      var error_code = error.code
      var error_message = error.message
 
      alert(error_message)
    });

  // ⇊ this is asynchronous, you should wait for it to finish
  firebase.database()
    .ref('/Studiopick/studio/users' + studioName)
    .set({ /* data */ });

  // this line gets called before any of the above tasks start firing
  alert("Studio Created");
  // followed by this line - which cancels everything above
  // before they complete
  window.location.href ="studiodash.html?id="+ uid;

  /* ... */
};

You must refactor your code to wait for the previous task to finish. To do this, first validate your form, and then afterwards call a new function that handles the leg work of creating the studio.

function handleNewStudioFormSubmit() { // renamed from newStudio
  // don't use alert - it blocks the thread
  console.log('debug: retrieving data... please wait')
  
  // Get data
  const studioName = document.getElementById("studioName").value,
    email = document.getElementById("email").value,
    password =  document.getElementById("password").value,
    firstName = document.getElementById("firstName").value,
    lastName = document.getElementById("lastName").value,
    phoneNumber = document.getElementById("phoneNumber").value;

  console.log({ studioName, firstName, email }); // note added braces here
  
  // Validate input fields
  if (!validate_email(email) || !validate_password(password)) {
    // TODO: replace this alert with updating the form with an error message
    alert('Error with email or password')
    return false // cancel submission
  }

  if (
    !validate_field(firstName) ||
    !validate_field(lastName) ||
    !validate_field(phoneNumber) ||
    !validate_field(studioName)
  ) {
    // TODO: replace this alert with updating the form with an error message
    alert('One or More Extra Fields is Outta Line!!')
    return false // cancel submission
  };

  createStudioThenOpenDashboard({
    studioName,
    firstName,
    lastName,
    email,
    password,
    phoneNumber
  })
    .catch((err) => {
      console.error('failed to create studio: ', err);
      alert('Failed to create studio. Cause: ' + err.message);
    });

  return false; // prevent form's default action (reload page), so that the async tasks above can complete.
}

// ⇊ permits using await
async function createStudioThenOpenDashboard(data) {
  const { email, password, studioName, ...otherData } = data;

  // creates the user, and waits for it to finish being created
  const { user } = await auth.createUserWithEmailAndPassword(email, password);

  // writes data to the database, and waits for it to complete
  await firebase.database()
    .ref('/studiopick/studio/users/' + studioName) // <-- note fixed path
    .set({
      ...otherData,
      studioName,
      email,
      uid: user.uid,
      // NEVER store passwords in plain text, even in testing
    });

  // once the above tasks succeed, navigate to the dashboard.
  window.location.href = "studiodash.html?id=" + user.uid
}

Don't forget to update

onclick="newStudio"

to

onclick="return handleNewStudioFormSubmit()"
Related