0

I have some HTML forms on the same page that are toggled sequentially one after another, after the previous one has been submitted. The user is able to navigate back and forth between them, so I need to remove submit event listeners after they have been triggered, so I can reattach them again if needed.

I am currently attaching submit event handlers inside the "rendering process" for each one of them, removing the event handler after executing the function like this:

form.addEventListener('submit', submitStepOne)

  function submitStepOne(e) {
      e.preventDefault()
      sendData()
      form.removeEventListener('submit', submitStepOne)
  }

same code for multiple form elements (submitStepTwo, submitStepThree…)

Because I don't want to keep repeating the same code, I want to create a global "submit step and go to next one" function, which I thought could look something like this:

const submitStep = (event, stepNo, trigger) => {
  event.preventDefault()
  toggleStep(stepNo)
  trigger.removeEventListener('submit', submitStep)
}

I thought I could attach the event handler to the submit button like this, using .bind() (tip from https://stackoverflow.com/a/23024673/10727821):

PAGES.step3.functions = function() {
  console.log('step 3')
  let trigger = this.domElement.querySelector('form')
  trigger.addEventListener('submit', submitStep.bind(null, event, 4, trigger))
}

PAGES is an object containing the DOM element for each of the steps as well as corresponding functions for each page. PAGES.stepX.functions() is called each time a step is toggled with toggleStep(step).

However, I'm getting an Uncaught TypeError: Cannot read property 'preventDefault' of undefined. How could I rewrite the function so I can properly pass parameters to it?

Thankful for any hints!

bruno
  • 369
  • 2
  • 15

1 Answers1

1

You are passing the event parameter when attaching the submitStep function, which at that point is undefined.

You would need to rearrange arguments of the submitStep so that event would be the last argument, then partially apply stepNo and trigger using .bind().

But there's another bug in your code. You are trying to remove event listener of the submitStep inside of it, which will not work after calling .bind(), as .bind() returns a new function. I would separate the event registration into a separate function, which would make a wrapper around the event handler and register the wrapper as the handler. Then during execution it would call the actual handler and unregister itself.

const addEventListenerOnce = (trigger, eventName, handler) => {
  // Create a function that will be registered as event handler
  const handlerWrapper = (event) => {
    // Call the actual handler
    handler(event);

    // Remove the registered wrapper
    trigger.removeEventListener(eventName, handlerWrapper);
  };

  // Register the wrapping function as event listener
  trigger.addEventListener(eventName, handlerWrapper);
};

const submitStep = (stepNo, event) => {
  event.preventDefault();
  toggleStep(stepNo);
}

PAGES.step3.functions = function() {
  console.log('step 3')
  let trigger = this.domElement.querySelector('form')
  // Only stepNo is applied, event is left
  // Function signature would be then (event) => void
  const submitHandler = submitStep.bind(null, 4);

  // Register the submit handler to be called once
  addEventListenerOnce(trigger, 'submit', submitHandler);
}
Krypt1
  • 1,066
  • 8
  • 14