bulma-tagsinput
bulma-tagsinput copied to clipboard
Detect whether DOM has already been created
Hi,
I'm desperately trying to get the tags input to work in combination with the Turbolinks framework. Turbolinks caches the DOM and restores the cached DOM on certain navigation events. That implies that the whole Javascript context persists accross page loads (App feels like an SPA)
When I attach the BulmaTagsInput using new BulmaTagsInput(someDOMElement), it will attach behavior and modify the element's DOM. This modified DOM is subsequently cached by the Turbolinks framework.
Now, when Turbolinks restores a DOM from its cache, it restores the already prepared BulmaTagsInput DOM, but not the associated BulmaTagsInput instance that is required to manage the component's state. Thus I need to create a new instance of BulmaTagsInput which inevitably performs the DOM modifications again in its constructor and I end up with multiple artificial DOM elements.
In order for this to work, the BulmaTagsInput would need to detect whether the required DOM elements have already been created and if so, opt put of creating them again. Or maybe you have some different ideas on how to get this to work?
Hi,
I don't know Turbolinks but I can take a look on your issue to see if you could share a working example on codepen.io or other online code editor.
I studied your code a little more and I think I gained a deeper understanding of what is really happening now.
When using BulmaTagsInput.attach(element)
attachalready stores theBulmaTagsInputinstance with the DOM element to which it belongs- Unfortunately, Turbolinks is caching a copy of the DOM. Copying leads to all the data and listeners being discarded. Text from Turbolinks documentation:
Turbolinks saves a copy of the current page to its cache just before rendering a new page. Note that Turbolinks copies the page using cloneNode(true), which means any attached event listeners and associated data are discarded.
- Your DOM observing code has no chance to identifiy the copy and thus creates a new
BulmaTagsInputinstance each time the DOM is restored from cache. - Creating the new instance also creates the DOM elements again (as by the instance's
this._init()andthis._build()calls)
I locally edited the _init() method and added the following lines:
_init() {
// reset DOM (makes _init and _build idempotent)
const tagsInputContainer = this.element.previousSibling;
if (tagsInputContainer && tagsInputContainer.classList && tagsInputContainer.classList.contains('tags-input')) {
tagsInputContainer.parentNode.removeChild(tagsInputContainer);
this.element.style.display = 'inline';
}
// ...
}
That's probably not he most effective way to make the DOM construction of BulmatagsInput idempotent, but it is exactly what helps in my case.
Regarding the codepen demo, that is not that easy, because one needs actual browser navigation events to demonstrate the behavior. However, I prepared a test instance of my application to show case the behavior in a real-life environment. I know that it is not as concise as a minimal codepen example, but it might help to get a feeling for the behavior I'm describing. I appreciate if you take the time to have a look at it.
Steps:
- Goto https://turbolinks.countmy.pizza/#create-anchor
- Enter arbitrary name and click 'Create Counter'
- You are now on your counter's page and should see the tags input
- Navigate back (to the front page) and forth (to the counter's page) using the browser's navigation buttons
-> Every time you navigate back to the counter's page, the page is restored from cache by
turbolinksand theBulmaTagsInputinitialization code is run again, leading to a stack of nested input fields.
I realize this might be an edge case for your library but I'd still be interested in your opinion on this.