NotFoundError: Node.removeChild: The node to be removed is not a child of this node

I’ve developed a theme component:

https://github.com/magjac/discourse-d3-graphviz

It replaces BBCode with SVG. This works also in the editor preview.

My problem is that in some cases I get an error when I type a character in the editor:

NotFoundError: Node.removeChild: The node to be removed is not a child of this node

I’m pretty sure that this is related to that I have removed some elements, because if I don’t remove anything, I don’t get the error.

EDIT: I doesn’t happen when I do the removal, but when I type the first character in the editor after the removal.

My question is if removing elements is not allowed?

If it is; Do you have any idea why I’m getting this error?

I realize this is kind of vague. I may be able to provide more details if necessary.

The stack trace can be seen here:

1 Like

EDIT 2: It’s not just elements that I remove. I sometimes remove only text nodes.

1 Like

I can reproduce this with this simple theme component:

<script type="text/discourse-plugin" version="0.8">

  api.decorateCooked($elem => {
    if ($elem.get(0).className == 'd-editor-preview') {
      const $paragraphs = $elem.children('p');
      $.each($paragraphs, (paragraphIndex, paragraph) => {
        paragraph.remove();
      });
    }
  });

</script>
  1. Create a new topic
  2. Start typing. The error appears in the dev console for the second character that is typed.
2 Likes

The composer preview uses ember to render the cooked content. It looks like that error is coming from the ember rendering engine, which is probably confused by the DOM being changed by something else.

To avoid the issue, I suggest that you don’t remove() any nodes, and instead hide them using display:none; or something similar.

3 Likes

Thanks. That’s a workaround I’ve been thinking of, but I would appreciate if you could confirm that this is a bug or not.

The composer preview is an unusual combination of ember rendering and custom ‘decorateCooked’ functions. It looks like this is a quirk of that implementation. We don’t have any plans to change the way it works at the moment, especially since the workaround is nice and simple.

4 Likes

@joffreyjaffeux I notice you have this cleanUp function passed to api.cleanupStream when you used WidgetGlue.

https://github.com/discourse/discourse-group-timezones/blob/master/javascripts/discourse/initializers/initialize-discourse-group-timezones.js.es6#L14-L17

I’m getting the error in the OP when I try to write in the composer after my widget attaches. Notably, the original div data-wrap is completely gone after I target it with WidgetGlue.appendTo()

EDIT: Solved. I create a sacrificial <div> node for the Widget to consume, so that I can leave the [wrap=dice] div alive.

  // elem: <div class="d-wrap" data-wrap="dice">

  //- const glue = new WidgetGlue("dice-result", register, attrs);
  elem.innerHTML = "";
  //- glue.appendTo(elem);
  const sacrificial = document.createElement("div");
  elem.appendChild(sacrificial);
  attachDiceWidget(sacrificial, attrs);
2 Likes