Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect whether DOM has already been created #14

Open
skuzzle opened this issue Aug 1, 2020 · 2 comments
Open

Detect whether DOM has already been created #14

skuzzle opened this issue Aug 1, 2020 · 2 comments

Comments

@skuzzle
Copy link

skuzzle commented Aug 1, 2020

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?

@CreativeBulma
Copy link
Owner

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.

@skuzzle
Copy link
Author

skuzzle commented Aug 3, 2020

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)

  1. attach already stores the BulmaTagsInput instance with the DOM element to which it belongs
  2. 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.

  1. Your DOM observing code has no chance to identifiy the copy and thus creates a new BulmaTagsInput instance each time the DOM is restored from cache.
  2. Creating the new instance also creates the DOM elements again (as by the instance's this._init() and this._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:

  1. Goto https://turbolinks.countmy.pizza/#create-anchor
  2. Enter arbitrary name and click 'Create Counter'
  3. You are now on your counter's page and should see the tags input
  4. 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 turbolinks and the BulmaTagsInput initialization 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants