JavaScript form fetch request submitting empty values when they are filled in

I am creating a Login form in JavaScript and am trying to send this form to my Ruby on Rails backend.

I have two problems:

  1. When the form loads, it triggers the eventListener and sends the blank form’s data to the backend. I have e.preventDefault() commented out in the second function below because I kept getting the error that it is not a function. Note: in the backend for Rails, I get the following message when I type in params. "Permitted: false" concerns me.
    <ActionController::Parameters {"controller"=>"sessions", "action"=>"create", "session"=>{}} permitted: false>

  2. When I fill in the form with an email and password and click the submit button, the loginData (from loginButton.addEventListener("submit", submitLogin(loginData) submits a blank value for the email and ‘password’ for the password (which are the default values I set to test the values) even though these elements are filled in in the form with an actual email address and password.

Function loading login form (note: this loads just fine):

  // create the elements
  var div = document.createElement("div"),
    log = document.createElement("div"),
    loginForm = document.createElement("form"),

  //set form attributes
  loginForm.setAttribute("method", "POST");

  // set body styles
  document.body.style.textTransform = "capitalize";

  log.id = "login";
  log.innerHTML = "login";

  // set loginForm styles
  loginForm.id = "loginForm";

  // set the elements and styles on the form
  loginForm.innerHTML =
    "<label>username</label><br/>" +
    "<input type='text' id='login-email' value='' placeholder='email' style='" +
    inputStyles +
    "' /><br/>" +
    "<label>password</label><br/>" +
    "<input type='password' id='login-password' value='value' placeholder='*************' style='" +
    inputStyles +
    "' /><br/>" +
    "<input type='submit' id='login-button' value='Login' style='" +
    btnStyles +
    "' />" +
    "<p><a style='" +
    forgetStyles +
    "' href='#'>forget password ?</a></p><br/>";
 
  // append the buttons and form on main-div
  div.appendChild(log);
  div.appendChild(loginForm);

  // append main-div on the body
  document.body.appendChild(div);

  //get login form values to submit
  let loginEmail = document.getElementById("login-email").value;
  let loginPassword = document.getElementById("login-password").value;
  let loginData = { member: { loginEmail, loginPassword } };
}

SubmitLogin Function (fetch request to Rails backend):

async function submitLogin(e) {
  // e.preventDefault();
  const loginData = new FormData(e.target);
  debugger;
  let options = {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Access-Control-Allow-Origin":
        "file:///Users/awb/Coding/Flatiron/Projects/bookclub-javascript-rails-api/bookclub-frontend-javascript/index.html",
      "Access-Control-Allow-Methods": "POST",
      "Access-Control-Allow-Headers": "Content-Type, Authorization",
      Accept: "application/json",
    },
    body: JSON.stringify(loginData),
  };

  fetch("http://localhost:3000/login", options)
    .then((resp) => {
      resp.json();
    })
    .then((member) => {
      console.log(member);
      return new Member(member);
    });
}

If it matters, this is the order of my scripts at the bottom of my index.html page:


    <script src="src/suggestion.js"></script>
    <script src="src/member.js"></script>
    <script src="src/gathering.js"></script>
    <script src="src/book_group.js"></script>
    <script src="src/book.js"></script>
    <script src="src/login_registration_form.js"></script>
    <script src="src/index.js"></script>

Where index.js calls the function "loadRegistrationLogin()" as the last line on index.js

My routes are:

Rails.application.routes.draw do
  resources :members, only [:create, :index, :show]
  resources :registrations, only: [:create]
  resources :sessions, only: [:create]
  
  post '/login', to: 'sessions#create'
  delete '/logout', to: 'sessions#destroy'
  get '/logged_in', to: 'sessions#is_logged_in?'

  root to: "static#home"
  
end

and finally, my session controller:

class SessionsController < ApplicationController
    include CurrentMemberConcern
    skip_before_action :verify_authenticity_token

    def create
        member = Member
        .find_by(email: params[:member][:email])
        .try(:authenticate, params[:member][:password])

        if member 
            login!
            render json: {
                status: :created, 
                logged_in: true,
                member: member 
            }
        else 
            render json: { 
                status: 401,
             errors: ['No such member', 'Verify credentials and try again or sign up']
            }
        end
    end
end

91 thoughts on “JavaScript form fetch request submitting empty values when they are filled in”

  1. Your form is submitting automatically because of the way you’ve set the event handler. The .addEventListener() API requires a reference to a callback function as the second argument. But you passed a function call with arguments like this:

    loginButton.addEventListener("submit", submitLogin(loginData));

    You have two choices to fix this:

    1. Pass a reference.
      • This will require loginData to be available to the handler in some other fashion.

    loginButton.addEventListener("submit", submitLogin);

    1. Enclose the call within a function expression:

    loginButton.addEventListener("submit", ()=>submitLogin(loginData));

    Option 2 is generally preferred when needing to pass parameters to the handler. But you’ll see below, for you, option one is the way to go.

    The leads to the next problem – submitLogin() function itself.

    async function submitLogin(e) {
      // e.preventDefault();
      const loginData = new FormData(e.target);
    

    In your eventListener setup you went out of your way to pass a parameter to this function – yet it isn’t used. You correctly attempt to create a new FormData() Object. But interestingly enough you pass e.target, which is the button element. That won’t work Reference.

    To fix that change:

    const loginData = new FormData(e.target);

    to: (assuming only one form on the page)

    const loginData = new FormData(document.forms[0]);

    But we aren’t done yet. Using e.preventDefault() is unnecessary if you set up your button correctly. A button with type="submit" is designed to submit the form to the server. That’s also true for a button with no type attribute at all. You clearly don’t want to submit the form, so don’t put a submit button on it.

    Change the login button from:

    type="submit"

    To:

    type="button"

    Now you can remove the e parameter from your function.

    All of that should get you a lot closer to success.

    Reply

Leave a Comment