skip to Main Content

I have a embeddable script that can be placed in the header of any host website. it fetched form and then attached submit event to them. it works in majority of the cases but on some websites, there are already event listeners attached to form. how can I make sure that my script works no matter the content of the host website. basically, if there are other event listeners attached to form, mine also gets executed

my current script

<script>

  const handleSubmit = async (event) => {
    event.preventDefault();
    //my api call
  };

  const addEventListenersToForms = () => {
    const forms = document.querySelectorAll("form");
    
    forms.forEach((form) => {
      if (!form.dataset.listenerAdded) {
        form.addEventListener('submit', handleSubmit);
        form.dataset.listenerAdded = 'true';
      }
    });
  };
  addEventListenersToForms();

</script>

i have tried multiple things but nothing is working out for me. one such case is captcha on form on some websites. this is just the example js code. basically my script will be deployed along with all the other code and a embeddable script will be given to users.

2

Answers


  1. It might be due to when "addEventListenerToForms" is being called cause if it called before the DOM is fully loaded, it won’t find the forms.

    There is many solutions i guess but the simplest one is wrapping your code inside DOMContentLoaded Eventlistener:

    document.addEventListener('DOMContentLoaded',(event)=>{
       // Your Code
    })
    
    Login or Signup to reply.
  2. Like also commented the event listeners will be called in the order that they are add. But the order also depends on the element that they are attached to and the use of the useCapture parameter on the addEventListener() method. So, the solution depends on the event listeners that are already listening for the submit event.

    First (to show the issue) an example of a setup where your event listener comes as the third out of four (five, with the overridden one):

    document.forms.form01.onsubmit = function(event){
      // this will "override" the onsubmit attribute on the form
      console.log(event.target.name, 'using the onsubmit property on the form');
    };
    
    document.onsubmit = function(event){
      console.log(event.target.name, 'using the onsubmit property on the document');
    };
    
    function handlerOnsubmitAttribute(event){
      console.log(event.target.name, 'using the onsubmit attribute on the form');
    }
    
    const firstHandleSubmit = (event) => {
      event.preventDefault();
      console.log(event.target.name, 'using the first addEventListener on the form');
    };
    
    document.forms.form01.addEventListener('submit', firstHandleSubmit);
    
    /** then comes your code **/
    
    const handleSubmitForm = async(event) => {
      event.preventDefault();
      console.log(event.target.name, 'using your event listener on the form');
      //my api call
    };
    
    document.forms.form01.addEventListener('submit', handleSubmitForm);
    <form name="form01" onsubmit="handlerOnsubmitAttribute(event)">
      <input name="test">
      <button>Submit</button>
    </form>

    Then an attempt to solve the issue

    If you use the useCapture parameter on the addEventListener() method and set it to true the event listener will be in the capturing phase, and the callback function will be called before all the event listeners in the bubbling phase (default is false). So, this only works if the other event listeners are NOT setting the useCapture to true

    Btw. In your case, where you have more forms, you can just add the event listener to the document or any other parent element of all the forms, and you don’t have to track if an event listener is added or not.

    document.forms.form01.onsubmit = function(event) {
      // this will "override" the onsubmit attribute on the form
      console.log(event.target.name, 'using the onsubmit property on the form');
    };
    
    document.onsubmit = function(event) {
      console.log(event.target.name, 'using the onsubmit property on the document');
    };
    
    function handlerOnsubmitAttribute(event) {
      console.log(event.target.name, 'using the onsubmit attribute on the form');
    }
    
    const firstHandleSubmit = (event) => {
      event.preventDefault();
      console.log(event.target.name, 'using the first addEventListener on the form');
    };
    
    document.forms.form01.addEventListener('submit', firstHandleSubmit);
    
    /** then comes your code **/
    
    const handleSubmitDocument = async(event) => {
      event.preventDefault();
      console.log(event.target.name, 'using your event listener on the document');
      //my api call
    };
    
    document.addEventListener('submit', handleSubmitDocument, true);
    
    const handleSubmitForm = async(event) => {
      event.preventDefault();
      console.log(event.target.name, 'using your event listener on the form');
      //my api call
    };
    
    document.addEventListener('submit', handleSubmitForm, true);
    <form name="form01" onsubmit="handlerOnsubmitAttribute(event)">
      <input name="test">
      <button>Submit</button>
    </form>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search