Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FIrefox doesn't preventing dispatched submit event

Speechless fiddle with reproducing of situation

The key code is:

class Form extends React.Component {
    handleSubmit(evt) {
        evt.preventDefault()

        var data = {}
        for (var i = 0; i < this.form.elements.length; i++) {
        var elt = this.form.elements[i]
          if (elt.name) {
            data[elt.name] = elt.value
          }
        }

        this.props.onSubmit(data)
        return false
    }

    submit() {
        if (this.form.checkValidity())
            this.form.dispatchEvent(new Event('submit'))
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit.bind(this)} ref={r => this.form = r}>
                {this.props.children}
            </form>
        )
    }
}

After this.form.dispatchEvent() the evt.preventDefault() in handleSubmit() doesn't work in Firefox

If you open fiddle in Chrome (e.g.) and enter data into fields, you will see it in console - the prevention of dispatched event will work perfectly.

In Firefox preventing doesn't work - after logging data the page immediately reloads (see "APP CONSTRUCTOR" in console).

So, the question is obvious: how to avoid this bug?

like image 664
Limbo Avatar asked Mar 31 '18 12:03

Limbo


1 Answers

First, this is not a react-specific question.

how to avoid this bug?

It seems that { cancelable: true } flag prevents Firefox from reloading the page in this case.

this.form.dispatchEvent(new Event('submit', { cancelable: true }))

Here's a full and simple example:

<!Doctype html>
<html>
  <head>
    <script type="text/javascript">
      document.addEventListener("DOMContentLoaded", function(event) {
        const form = document.querySelector('#testform');
        const button = form.querySelector('button');

        form.onsubmit = function (e) {
          e.preventDefault();
          e.stopPropagation();

          console.log('submitting the form ...');
          
          // return true;
          return false;
        };

        // https://developer.mozilla.org/en-US/docs/Web/API/Event/Event
        // cancelable: (optional) a Boolean indicating whether the event can be cancelled. The default is false.
        const submitEvent = new Event('submit', { 
          cancelable: true
        });

        // https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted
        // The isTrusted read-only property of the Event interface is a boolean that is true when the event was generated by a user action, and false when the event was created or modified by a script or dispatched via dispatchEvent.
        console.log('is event trusted', submitEvent.isTrusted) // false
        console.log('is event cancelable', submitEvent.cancelable) // true

        button.onclick = function () {
          console.log('button clicked');
          const cancelled = form.dispatchEvent(submitEvent);
          // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent
          // The return value is false if event is cancelable and at least one of the event handlers which handled this event called Event.preventDefault(). Otherwise it returns true.
          console.log('is cancelled', !cancelled);
        }
      });
    </script>
  </head>
  <body>
    <form id="testform">
      <input type="hidden" name="a" value="b">
      <p>Hit the button a couple times, the page should not refresh.</p>
      <button type="button">click</button>
    </form>
  </body>
</html>

Why this happens:

https://www.chromestatus.com/features/5718803933560832 According to the UI Events specification un-trusted events (i.e. those created by JavaScript) should not invoke the default action.

If you change the cancelable flag to false and try the test in Chrome, it would still work, because (as far as I understand) it is still an untrusted event (created not by direct user interaction with UI) and Chrome does not run default handlers for untrusted events.

But, I'm not sure why Firefox still runs default handlers for untrusted events.

like image 128
Nik Markin Avatar answered Nov 03 '22 23:11

Nik Markin