mithril.js: Input `onchange` doesn't fire if container has `onmousedown` handler

Hello! I’ve really enjoyed using mithril.js, thanks for all the hard work everyone has put into it. I may have run into a troublesome bug for mithril version 0.2.5.

Description:

The onchange handler for an <input type='text'> element does not fire if the following three conditions are met:

  1. A parent div has an onmousedown handler set
  2. The value attr of the input is manually specified in the view function
  3. Focus for the input element is lost by clicking anywhere in the parent div

Setting onclick for the parent container does not cause this problem. I didn’t test any other mouse events.

Steps to Reproduce:

var App = {
  controller: function() {
    this.text = '';
  },
  view: function(ctrl) {
    return m('.container', {
      // Setting this handler seems to enable the bug
      onmousedown: function noop() {}
    }, [
      m('input', {
        type: 'text',
        // This handler won't fire if we lose focus by clicking inside the container
        onchange: function(e) {
          ctrl.text = e.target.value;
          console.log('input onchange just fired');
        },
        // Removing this line does cause the `onchange` to fire properly, but that's a non-solution
        value: ctrl.text || ''
      })
    ]);
  }
};

Here is a fiddle that is built around the above code example: https://jsfiddle.net/cyLvcqpo/8/

Expected:

The onchange handler should fire when we enter text into the input and then click on the parent div.

Actual:

The onchange handler does not fire when we enter text into the input and then click anywhere in the parent div.

Importantly, this problem doesn’t occur in vanilla JS. Setting an onmousedown handler on a parent element does not prevent onchange handlers from firing for input elements when focus is lost by clicking inside the parent.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 15 (10 by maintainers)

Most upvoted comments

👍 for making autoredraw async. The impression I got from the motion to remove sync redraw from the API was that synchronous draw was generally full of danger which should be kept away from unwitting users - going by that logic it should definitely not be the default for event handler autoredraw.

👍 for making autoredraw async.

With the force of a thousand Shia Labeouf, @lhorie DO IT!

(with due apologies for being insistent…)

Seems likely, mousedown probably triggers blur which triggers change, then mouseup fires when you release the mouse button and click happens immediately after that.

I’d probably use oninput for this myself so the field/data-model were kept in sync on every change of the <input> field’s value. Haven’t tested it but I’m pretty confident that it wouldn’t have the same event ordering issue.

@lhorie is going to experiment w/ making the automatic redraw after DOM events run asynchronously (in 1.0.0) which may or may not alleviate this particular situation.