Ilari Mäkimattila
Ilari Mäkimattila

Reputation: 103

Delay submitting a form in Chrome

I want to fire and forget a request, with a short grace time, when user clicks a link or submits a form. Here's a simplified code that I'm using:

element.addEventListener(eventType, function(event) {
  if (event.retriggered) {
    return true;
  }

  let target = event.target;
  let newEvent = new event.constructor(event.type, event);
  newEvent.retriggered = true;

  setTimeout(() => {
    target.dispatchEvent(newEvent);
  }, 250);

  // fire and forget the request
  makeRequest();

  event.preventDefault();
  return false;
});

This works fine for click events and it works fine for submit event in Firefox but not in Chrome. I've created a fiddle here. In Firefox, if you click the button, you can see that the browser makes a GET request, but that does not happen in Chrome. According to my tests the original and new event look the same in both browsers and dispatchEvent returns true. Still, the actual submit is not triggered in Chrome, so I'm wondering is Chrome stopping the submit as a security measure or did I miss something?

Upvotes: 2

Views: 422

Answers (1)

Thijs
Thijs

Reputation: 2351

The event you are dispatching is at least a little different from the event you're trying to copy. Your event has the isTrusted property of the event set to false. Perhaps this is the reason why Chrome doesn't submit the form.

What I do know is how you can your desired result, for forms, with slightly different code. I've based this on the code in your Fiddle so it now handles just the form submit.

let 
  form = document.getElementById('form');

form.addEventListener('submit', function(event) {
  setTimeout(() => {
    form.submit();
  }, 250);

  event.preventDefault();
});
<form id="form" method="get" action="/echo/html/">
  <button type="submit">Go</button>
</form>

Instead of dispatching the submit event yourself, you can just call the submit() method of the form. This will submit the form but doesn't cause any submit handlers to be fired (as per this MDN article). It will save you the check in the handler to see if the submit should be delayed or not.

You could adjust it to also work with anchors.

let 
  form = document.getElementById('form'),
  anchor = document.getElementById('anchor');

function onDelayNavigationEvent(event) {
  const 
    target = event.target;
    
  if (target.hasAttribute('is-delayed')) {
    return true;
  }
  
  setTimeout(() => {
    if (target.tagName.toLowerCase() === 'form') {
      target.submit();
    } else {
      target.click();
    }
  }, 2000);
  
  target.setAttribute('is-delayed', true);
  event.preventDefault();
}

function delayNavigation(element, eventName) {
  element.addEventListener(eventName, onDelayNavigationEvent);
}

delayNavigation(form, 'submit');
delayNavigation(anchor, 'click');
<form id="form" method="get" action="/echo/html/">
  <button type="submit">Go</button>
</form>

<a id="anchor" href="//stackoverflow.com">Stack Overflow</a>

Upvotes: 1

Related Questions