56

I'm using http://alexgorbatchev.com/SyntaxHighlighter/ to highlight code on my website but sometimes in my log im getting Javascript errors like this :

Uncaught NotFoundError: 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?

Uncaught NotFoundError: An attempt was made to reference a Node in a context where it does not exist.

// set up handler for lost focus
attachEvent(textarea, 'blur', function(e)
{
   textarea.parentNode.removeChild(textarea);
   removeClass(highlighterDiv, 'source');
});

Here is the attachEvent() function code :

function attachEvent(obj, type, func, scope)
{
    function handler(e)
    {
        e = e || window.event;
        
        if (!e.target)
        {
            e.target = e.srcElement;
            e.preventDefault = function()
            {
                this.returnValue = false;
            };
        }
            
        func.call(scope || window, e);
    };
    
    if (obj.attachEvent) 
    {
        obj.attachEvent('on' + type, handler);
    }
    else 
    {
        obj.addEventListener(type, handler, false);
    }
};

Can anyone help getting this fixed ?

Community
  • 1
  • 1
scootergrisen
  • 1,003
  • 1
  • 11
  • 20
  • what is textarea html ? if possible make a fiddle. – Neha Feb 21 '14 at 05:36
  • 1
    textarea = document.createElement('textarea') you can se it in the full source. You can try this demo http://netkoder.dk/netkoder/eksempler/eksempel0009.html but the error dont accure normally. I only get the error sometimes in my website log that logs javascript errors. – scootergrisen Feb 21 '14 at 05:54
  • *attachEvent*? Where has that come from? Sorry, don't feel like wading through 4 script files to find it. – RobG Feb 21 '14 at 06:46
  • Its in the same file in the link above. – scootergrisen Feb 21 '14 at 20:50
  • Maybe this is the sulution to test if the node exists before trying to remove it, can someone confirm that this will make the error message go away ? : if (textarea.parentNode) { textarea.parentNode.removeChild(textarea); } – scootergrisen Feb 21 '14 at 20:57

11 Answers11

70

I had to deal with the same issue, and the answer is confusing and counter intuitive. Well, it has its logic, but leads to non-trivial behaviours.

Essentially, when a node is removed from the DOM tree, it fires a blur event (and before a focusout event too).

So, when you call removeChild, the blur event is fired again, but this time textarea still has its parentNode defined, but textarea isn't among its parent's children anymore! (Yes, read this twice. Or more.)

This happens in Chrome for now, although Firefox has planned to do the same for quite some time.

As a workaround, you can remove the event listener you attached:

var onblur = function(e) {
    detachEvent(textarea, 'blur', onblur);
    textarea.parentNode.removeChild(textarea);
    removeClass(highlighterDiv, 'source');
};
attachEvent(textarea, 'blur', onblur);

I'm assuming that you have some detachEvent function to remove event listeners. Adjust the code to your needs.

Alternatively, you can set a flag (like a property, or an attribute, or better a scoped variable) on the textarea in the listener function, and check for it before proceeding with the node removal:

var removed = false;
attachEvent(textarea, 'blur', function(e) {
    if (removed) return;
    removed = true;
    textarea.parentNode.removeChild(textarea);
    removeClass(highlighterDiv, 'source');
});

You can also check if textarea if actually a child node of its parentNode before removing it, but such test is so counter-intuitive (at least to me) that I wouldn't recommend doing that, in fear that this behaviour will be changed in the future.

Finally, you can always rely on a try...catch statement, but... ugh.

2016 Update

Naturally, using a framework like jQuery would save you a lot of work attaching event listeners with one, but this functionality will come to standard addEventListener too:

textarea.addEventListener('blur', handler, { once: true });
MaxArt
  • 22,200
  • 10
  • 82
  • 81
  • Thanks. I dont understand but do you know how to change the code to avoid the error ? – scootergrisen Apr 08 '14 at 15:20
  • @scootergrisen Yes, I edited my answer to include a couple of solutions. – MaxArt Apr 08 '14 at 15:39
  • 5
    Definitely use `try...catch` for crap like that. – OCDev May 08 '15 at 23:22
  • Saved my ass, been debugging this for two hours already! Didn't know that blur was triggered... – Mārtiņš Briedis Jun 29 '15 at 15:08
  • 1
    @OCDev I understand the feeling, but semantically, a `try...catch` should be used for unpredicted behaviours that we don't want to break the code (or for, say, feature detection). As odd as it may sound, this is actually a documented, standard case. – MaxArt Oct 29 '15 at 22:54
18

While the classic answer for this question was that it's a bug in the JS code, with React 16 there is a major bug which means that any browser/extension mechanism which modifies the DOM breaks React.

Google Chrome's built in Translate functionality is the most common culprit.

GitHub issue: https://github.com/facebook/react/issues/11538

Minimal case: https://p93xxmr0rq.codesandbox.io/ (just manually right click "Translate to" in Chrome and select from Japanese then click the button)

Workaround: How to disable google translate from html in chrome

<meta name="google" content="notranslate">
hyperknot
  • 13,454
  • 24
  • 98
  • 153
  • I tried many solutions, and finally after reading your comment, I disabled google auto translate. And now the error is gone and no longer react crashes. Thanks. – rushil Feb 14 '19 at 11:59
  • Disable google translate might not be the best solution for your app from a UX perspective. However from a DX perspective it is a good solution. There is a work around other than disabling google translate completely https://github.com/facebook/react/issues/11538#issuecomment-390386520 – rotimi-best Feb 03 '20 at 13:59
  • Replacing React.Fragment with `span` fixed issue for me. – Jeyhun Ashurbayov Oct 21 '22 at 07:52
11

Try to translate your site with Google Chrome (right click on the site and choose "Translate to English". If you see the error happening in the console, then you know it's caused by Google Translate.

Related GitHub issue: https://github.com/facebook/react/issues/11538.


Workaround from Dan Abramov:

if (typeof Node === 'function' && Node.prototype) {
  const originalRemoveChild = Node.prototype.removeChild;
  Node.prototype.removeChild = function(child) {
    if (child.parentNode !== this) {
      if (console) {
        console.error('Cannot remove a child from a different parent', child, this);
      }
      return child;
    }
    return originalRemoveChild.apply(this, arguments);
  }

  const originalInsertBefore = Node.prototype.insertBefore;
  Node.prototype.insertBefore = function(newNode, referenceNode) {
    if (referenceNode && referenceNode.parentNode !== this) {
      if (console) {
        console.error('Cannot insert before a reference node from a different parent', referenceNode, this);
      }
      return newNode;
    }
    return originalInsertBefore.apply(this, arguments);
  }
}

Run this code before your app is rendered. Please keep in mind, that this has a slight performance hit.


Workaround from Shuhei Kagawa

Render texts in <span>.

// Case 1
<div>
  {condition && 'Welcome'}
  <span>Something</span>
</div>

// A workaround for case 1
<div>
  {condition && <span>Welcome</span>}
  <span>Something</span>
</div>

// Case 2
<div>
  {condition && <span>Something</span>}
  Welcome
</div>

// A workaround for case 2
<div>
  {condition && <span>Something</span>}
  <span>Welcome</span>
</div>

A detailed explanation can be found here: https://github.com/facebook/react/issues/11538#issuecomment-390386520

Dávid Molnár
  • 10,673
  • 7
  • 30
  • 55
6

I'm going out on a limb here and assuming that some of you who find this question are here because you googled the error quoted above:

'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?

I'm using jQuery & DataTables 1.10.6 and this error was indeed coming up on a blur() event where I was updating the cell value. The solution for me was to add a condition inside the event like this:

var blur = false;
$('table').on('blur', 'td select', function() {
    if (!blur) {
        blur = true;
        var cell = $(this).closest('td');
        table.cell(cell).data('example data');
        blur = false;
    }
});

I would be very surprised if there weren't a much better solution but hopefully this helps someone and maybe garners some constructive comments.

  • 3
    @Fusion - I get that, and generally I'm not in the habit of posting jQuery answers on javascript tagged questions. However the reason for this post is that I encountered the exact same error **because of jQuery** and DataTables. True, it's not specifically addressing the question, but I'm addressing the error he mentioned in the context where I encountered it. As this was the top google result I found, the chances of someone arriving here and finding this answer useful are as good as any. Sometimes I post answers for the sake of more people the the OP. – But those new buttons though.. Feb 22 '16 at 22:54
  • 1
    Ding! that's how you do it! – Craig Sep 15 '16 at 18:45
  • Just want to update the answer here as there is an error in it. Within your event handler function you are setting blur to true and then to false. This won't work, you just need to set blur to true at the end like so: ` $('table').on('blur', 'td select', function() { if (!blur) { var cell = $(this).closest('td'); table.cell(cell).data('example data'); blur = true; } });` – jjsquared Mar 26 '20 at 23:00
  • How do i format code in comments it is not letting me even with 3 back ticks – jjsquared Mar 26 '20 at 23:07
  • I actually had additional code before the `blur = false` which is why it wasn't working for me. Once i moved that statement to the end of my codeblock it worked for me. Also this is when using `focusout()` and not `blur()` in my instance. – jjsquared Mar 26 '20 at 23:11
  • @jjsquared - If you need help specific to your code you should open a new question. There's nothing wrong with the logic in my code as it stands. – But those new buttons though.. Mar 26 '20 at 23:26
3

I use Time delay and it work for me like this.

    // set up handler for lost focus
    attachEvent(textarea, 'blur', function(e)
    {
        setTimeout(function() {
            textarea.parentNode.removeChild(textarea);
            removeClass(highlighterDiv, 'source');
        }, 0);
    });
2

Instead of textarea.parentNode.removeChild(textarea); You could use textarea.parentNode.innerHTML = '' or something similar, depending on your context.

R-J
  • 928
  • 1
  • 7
  • 24
2

I was getting this error and nothing from above helped me, eventually I ended up with just simple :

if (img.parentNode) {
    body.removeChild(img);
}

which works perfectly for me.

1

I found the same error message on a simple jQuery script. When I tried to get the height of an element $('#element').height() I saw the same error on the console.

The element exists and $('#element').length was 1.

The log of the element with console.log( $('#element') ) was like a jQuery object but with a lot of methods repeated.

After a lot of debugg I found that adding a $(document).on('DOMContentLoaded DOMNodeInserted') event handler made this weird thing to jQuery objects.

Hope this help someone cause It's hard to find.

0

The event types may be different when it's fired from the program verses from the default action of the Dom. If you check the types, and use an if (type === 'typeYouWant') as a guard clause, you can potentially skip the unwanted execution of your code. Console log the event to check if there's a 'type' you can isolate.

   formEditEl.addEventListener('blur', this._cancelEdit.bind(this));

  _cancelEdit(e) {
    if (e.type === "change") document.querySelector('.form__edit').remove();
    };
Scott Eifel
  • 81
  • 1
  • 3
-1

you need to check each time the method is executed whether the element is a child of the given parent.

if(box.parentElement === parentBox) {
    parentBox.removeChild(box);
}
lmiguelvargasf
  • 63,191
  • 45
  • 217
  • 228
Ilya Rogatkin
  • 69
  • 1
  • 7
-2

Why dont you use jquery:

$("#element_id").remove();
unresolved_external
  • 1,930
  • 5
  • 30
  • 65