yairEO / tagify

🔖 lightweight, efficient Tags input component in Vanilla JS / React / Angular / Vue
https://yaireo.github.io/tagify/
Other
3.55k stars 436 forks source link

Fix error when DOM element is already detached during call to destroy method #1388

Closed blutorange closed 4 weeks ago

blutorange commented 1 month ago

This adds a check to the destroy method whether the this.DOM.scope.parentNode exists before accessing it to remove this.DOM.scope.

this.DOM.scope.parentNode can be null when the element was already removed from the DOM. The destroy method then throws an error. This is bad because the following code won't run anymore, and e.g. the listeners set via setInterval won't get cleared anymore. It seems you had already considered this case here:

        observeOriginalInputValue(){
            // if, for some reason, the Tagified element is no longer in the DOM,
            // call the "destroy" method to kill all references to timeouts/intervals
            if( !this.DOM.originalInput.parentNode ) this.destroy()

But that doesn't quite work yet, since destroy throws when this.DOM.originalInput.parentNode is null.

For context, we came across this issue when we wrapped tagify as PrimeFaces widget. This UI framework first detaches widgets from the DOM, then calls their destroy method. As a result, the setInterval kept getting fired and tagify tried to destroy itself over and over again, resulting in many error messages getting logged.


You can reproduce like this:

https://jsfiddle.net/blutorange/9ers8qtp/

<html>
  <body>
  <div id="container">
     <input id="myTag">
     <button id="detach-destroy">remove from DOM</button>  
  </div>
  </body>
</html>
instance = new Tagify(document.getElementById("myTag"))
document.getElementById("detach-destroy").addEventListener("click", () => {
  instance.DOM.scope.remove();
  document.getElementById("myTag").remove();
});

Screencast from 2024-10-08 19-31-44.webm