Mithril.js: Uncaught DOMException: Failed to execute 'removeChild' on 'Node'

Created on 3 Apr 2017  路  20Comments  路  Source: MithrilJS/mithril.js

Steps to Reproduce:

  1. Make changes in an input that has an oninput event.
  2. Immediately navigate to another page using the browser's back or forward button.

Environment: Mithril 1.0.1 on Chrome 56.0.2924.87 (Windows 10).

Previous Related Issue: #358

Sample Code:

module.exports =
  { oninit:
      vn => {
              const id = Number( vn.attrs.id )
              const stream = M.loadItem( id )
              vn.state.data = { id, stream, initial: stream() }
            }
  , view: vn =>
    <div>
      <label class="label">
        Last Name
        <input
          class="input"
          type="text"
          placeholder="Last Name"
          onchange={ X.setStreamPropToValueAttr( vn.state.data.stream )( 'lastName' ) }
          value={ X.getStreamProp( vn.state.data.stream )( 'lastName' ) }
        />
      </label>
    </div>
  }
Needs reproduction Bug

All 20 comments

@kurtmilam Just to be sure, does this happen when you navigate to another page, or on routed components, and you navigate back to a previous route?

Also, @kurtmilam, could you verify it also repros with v1.1.0 (the latest release)?

@pygy This occurs on routed components when I navigate to a previous route using the browser's back or forward buttons. I believe it's due to the fact that the action that triggers the input's onupdate event also causes the input to be removed from the DOM.

@isiahmeadows I have just verified that the described behavior still occurs with mithril v1.1.0 .

@kurtmilam One last thing: could you edit your repro down to something that doesn't require external functions?

@isiahmeadows I've just confirmed that the behavior persists when the component in question is stripped to bare bones:

import m from 'mithril'
module.exports =
  { view: vn =>
      <input onchange={ console.log } />
  }

It persists when I swap out the JSX syntax for javascript:

import m from 'mithril'
module.exports =
  { view: vn =>
      m( 'input', { onchange: console.log } )
  }

It persists when I switch to ES5 syntax, getting rid of the arrow function:

import m from 'mithril'
module.exports =
  { view: function () {
      return m( 'input', { onchange: console.log } )
    }
  }

@kurtmilam JSX is okay. I just needed a minimal workable repro.

How are you redrawing the component?

@isiahmeadows I wanted to eliminate all possible variables 馃槣

The component is drawn on a specific route. The 'app' is just an experiment based on an extended version of the simple application (from the mithril docs). The behavior occurs when I change an input on my '/edit/:id' route, then navigate back to the '/list' route while focus is still in the input.

I'm seeing probably the same error with Mithril v1.1.6:

mithril.v1.1.6.js:817 Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is no longer a child of this node. Perhaps it was moved in a 'blur' event handler?
    at removeNodeFromDOM (http://localhost:8334/pointrel20171122/bootstrap/mithril.v1.1.6.js:817:30)
    at continuation (http://localhost:8334/pointrel20171122/bootstrap/mithril.v1.1.6.js:806:6)
    at removeNode (http://localhost:8334/pointrel20171122/bootstrap/mithril.v1.1.6.js:794:3)
    at updateNode (http://localhost:8334/pointrel20171122/bootstrap/mithril.v1.1.6.js:635:4)
    at updateNodes (http://localhost:8334/pointrel20171122/bootstrap/mithril.v1.1.6.js:556:6)
    at updateElement (http://localhost:8334/pointrel20171122/bootstrap/mithril.v1.1.6.js:687:4)
    at updateNode (http://localhost:8334/pointrel20171122/bootstrap/mithril.v1.1.6.js:629:15)
    at updateNodes (http://localhost:8334/pointrel20171122/bootstrap/mithril.v1.1.6.js:537:12)
    at updateElement (http://localhost:8334/pointrel20171122/bootstrap/mithril.v1.1.6.js:687:4)
    at updateNode (http://localhost:8334/pointrel20171122/bootstrap/mithril.v1.1.6.js:629:15)

I don't have it isolated to a simple case. In my situation, it seems to happen in a drawing app I am writing when I click onto some SVG objects and the app removes some input fields being displayed associated with a different SVG object. The consequence is it leaves the old input fields displayed alongside new ones.

This might be the root cause and some possible solutions:
https://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node#22934552

Edit: I am seeing this in Chromium 63. I have not tested this with Firefox.

Great...so something we need to work around internally (i.e. don't actually call the callback if we're currently removing the node)? 馃槮

Edit: Thanks for the link! It's very informative. (That's a super odd DOM edge case, though.)

So finally, a fix incoming in #2286.

We need a working self-contained repro that reproduces it at least some of the time. Could one of you all experiencing it put together a Flems? It doesn't have to be minimal, just self-contained.

I'd be happy to work up a repro, but I'm not sure it'll work in flems or code sandbox (just tried in both), since I only saw the error when I used the browser's forward or back button to navigate to a different route in my mithril application while my input still had focus.

@kurtmilam If you have to, drop a debugger statement in the view of an offending component and try stepping through it. That might help you in isolating a repro case.

Alternatively, you could do input.focus() + location.hash = ....

@kurtmilam you can post it as a gist then?

Filename: index.html, load Mithril through https://unpkg.com/[email protected], then we can load it with bl.ocks.org which is just a gist viewer.

@kurtmilam Do note that iframes do still work with hash navigation and history navigation.

@kurtmilam Found anything reproducible yet? At this point, we're not even looking for anything minimal, just self-contained (even if it means slapping together a full repo we have to clone).

PSA: I don't care if it's a website at this point - as long as you can point me to where the functionality breaks, I'm willing to reverse engineer minified JS and place strategic breakpoints if I have to to isolate this bug.

I was able to reproduce this on Chrome 53 (probably the version I was using when I initially reported this issue), but have not been able to reproduce it on Chrome 70 or the latest versions of Firefox or Safari.

I reproduced it using this flems experiment.

Steps to reproduce:

  1. Go to the flems.
  2. Click on any user's name to open the /user/{id} route.
  3. Type a few characters into the input.
  4. While the input still has focus, use the browser's back button to navigate back to the /list route.

et voila!

Screen shot (a little messy because I was running a virtual copy of Chrome 53 on turbo.net):
image

Apologies that it's taken so long to help track this down.

@kurtmilam Yeah, that reads like a browser bug we can't really work around, especially if setting the hash directly doesn't trigger identical behavior. Given it takes a seriously old Chrome version for it to repro, I'm not sure we can fix it. BTW, we only support the last 2 versions of Chrome, so you need to create a repro that works on one of those.

Closing for now. If anyone can reproduce this bug again, please file a new issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

andraaspar picture andraaspar  路  4Comments

volnei picture volnei  路  3Comments

StephanHoyer picture StephanHoyer  路  4Comments

designMoreWeb picture designMoreWeb  路  4Comments

tivac picture tivac  路  3Comments