Giter Club home page Giter Club logo

Comments (22)

excid3 avatar excid3 commented on June 16, 2024 1

Looks like it's an open issue with Turbo: hotwired/turbo#117

PR with a fix is in main but unreleased. Try testing against turbo's main branch and let me know if that fixes it!

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024 1

I've tried both hotwired/turbo#169 and hotwired/turbo#162, neither seem to fix the issue described above. The page seems to be cached prior to the stimulus#disconnect logic being executed.

For now, I'll stick with the turbo:before-cache workaround.

$(document).on('turbo:before-cache', function() {
  $('[data-controller="dropdown"] [data-dropdown-target]').addClass('hidden');
});

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024 1

Adding the following to tailwindcss-stimulus-components's src/dropdown.js

  connect() {
    console.log("DropdownController#connect");

...

  disconnect() {
    console.log("DropdownController#disconnect");

and the following to my own project:

$(document).on('turbo:click', function() {
  return console.log('turbo:click');
});

$(document).on('turbo:before-visit', function() {
  return console.log('turbo:before-visit');
});

$(document).on('turbo:visit', function() {
  return console.log('turbo:visit');
});

$(document).on('turbo:submit-start', function() {
  return console.log('turbo:submit-start');
});

$(document).on('turbo:before-fetch-request', function() {
  return console.log('turbo:before-fetch-request');
});

$(document).on('turbo:before-fetch-response', function() {
  return console.log('turbo:before-fetch-response');
});

$(document).on('turbo:submit-end', function() {
  return console.log('turbo:submit-end');
});

$(document).on('turbo:before-cache', function() {
  return console.log('turbo:before-cache');
});

$(document).on('turbo:before-render', function() {
  return console.log('turbo:before-render');
});

$(document).on('turbo:before-stream-render', function() {
  return console.log('turbo:before-stream-render');
});

$(document).on('turbo:render', function() {
  return console.log('turbo:render');
});

$(document).on('turbo:load', function() {
  return console.log('turbo:load');
});

Using "@hotwired/turbo-rails": "^7.0.0-beta.5" defined via the package.json, the output is as follows:

Initial page load:

turbo:load
DropdownController#connect

Click a link in the dropdown (or simply navigate to another page)

turbo:click
turbo:before-visit
turbo:before-fetch-request
turbo:visit
turbo:before-fetch-response
turbo:before-cache
turbo:before-render
DropdownController#disconnect
DropdownController#connect
turbo:render
turbo:load

The turbo:before-cache is clearly happening before the DropdownController#disconnect is called.

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024 1

This is what caught my attention. That, regardless the desired intention and how it could be achieved by the library:
1. you would like to manipulate dom before caching
2. you expected that if you did so from the disconnect method
3. you expected the cached page would be the result of the manipulation. just like it was happening using turbolinks after the (turbolinks/turbolinks#390)

Yes, my expectation was that any manipulation via the controller disconnect method would be applied before the page was cached. That expectation was based upon turbolinks/turbolinks#390 (comment)

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024 1

Using "@hotwired/turbo-rails": "^7.0.0-beta.5" defined via the package.json, the output is as follows:

Would you like me to test against Turbo's main branch? Did you find an easy way to do this? I have both turbo-rails and turbo checked out locally. I'm assuming the easiest way is to copy the relevant files into my project's node_modules/@hotwired/turbo/dist/ (and node_modules/@hotwired/turbo-rails/app/assets/javascripts/turbo.js)?

from tailwindcss-stimulus-components.

thanosbellos avatar thanosbellos commented on June 16, 2024 1

Even without animations i see the menu closing rapidly after restoring from the cache. But it does close something that is crucial in general.

Just to confirm, this doesn't happen when using tailwindcss-stimulus-components by default, the dropdown is always open after restoring from the cache?

Once this.hide() is added to the tailwindcss-stimulus-components dropdown controller disconnect method, I experience what you have described:

the menu closing rapidly after restoring from the cache.

Exactly. those were my findings using the modified version that calls hide when the controller disconnects and for either library(turbolinks and turbo)

from tailwindcss-stimulus-components.

excid3 avatar excid3 commented on June 16, 2024

The only thing I can think of would be adding and removing a turbo:before-cache callback listener in the controller automatically. I imagine that the before-cache event will typically fire first because the Stimulus controller won't disconnect until the page is replaced.

Probably all of the components would need this, since you probably want to reset all of them before-cache.

from tailwindcss-stimulus-components.

excid3 avatar excid3 commented on June 16, 2024

Found this on Turbolinks: turbolinks/turbolinks#390

I would assume Turbo is supposed to work similarly. Maybe something is wrong with this functionality.

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024

from tailwindcss-stimulus-components.

excid3 avatar excid3 commented on June 16, 2024

It's probably a combination of the Turbo disconnect at the right time, and we need to make sure we close dropdowns, etc on disconnect (which I don't believe we do right now).

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024

From looking at turbolinks/turbolinks#390 which you linked to above, it looks like Turbolinks was updated to defer the snapshot caching until after the stimulus disconnect. Turbo does not seem to be working in the same way.

we need to make sure we close dropdowns, etc on disconnect (which I don't believe we do right now).

I have made this change locally, but as mentioned above, it's not quite working as expected with Turbo. I'll switch back to a Turbolinks setup and see what happens there, and depending on the outcome, I'll open a PR with the changes.

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024

Having thought about this some more, I think the issue can be resolved in tailwindcss-stimulus-components.

Turbo is doing the correct thing by snapshot'ing the state of the page upon departure, so we need to get the page into the correct state when a user is leaving the page via clicking a link in the dropdown menu, e.g. upon selecting a link in the dropdown, the dropdown should be closed. This appears to happen as a new page is rendered, however, the dropdown is actually still open.

Solution 1:

The user is responsible for adding Stimulus markup on the dropdown items: e.g: data-action="click->dropdown#toggle"

<div data-controller="dropdown" aria-haspopup="true" aria-expanded="false">
  <div aria-haspopup="true" aria-expanded="false">
    <button data-action="click->dropdown#toggle click@window->dropdown#hide">
      <span>Button label</span>
    </button>
  </div>
  <div data-dropdown-target="menu">
    <div>
      <div role="menu" aria-orientation="vertical">
        <a role="menuitem" data-action="click->dropdown#toggle" href="#">Option 1</a>
        <a role="menuitem" data-action="click->dropdown#toggle" href="#">Option 2</a>
        <a role="menuitem" data-action="click->dropdown#toggle" href="#">Option 3</a>
      </div>
    </div>
  </div>
</div>

Solution 2:

The Stimulus DropdownController#connect method binds a listener, so that the dropdown menu is closed when an option is clicked

    if (this.hasMenuTarget) {
      $(this.menuTarget).on("turbo:click", (event) => {
        this.hide()
      });
    }

Both of these solutions work as expected when using Turbo. If you let me know your thoughts I can look to get a PR opened.

from tailwindcss-stimulus-components.

thanosbellos avatar thanosbellos commented on June 16, 2024

Hi @davegudge i was about to close the issue on Turbo's repository but i found out about your issues. I have some questions/notes:

  1. Did adding this.hide() on your controller's disconnect method have the desired effect, while using the latest public version of Turbo(v.7.0.0.beta4) or some the pull requests mentioned in (hotwired/turbo#117)
  2. Did adding this.hide() on disconnect work with Turbolinks?

Turbo is doing the correct thing by snapshot'ing the state of the page upon departure, so we need to get the page into the correct state when a user is leaving the page via clicking a link in the dropdown menu, e.g. upon selecting a link in the dropdown, the dropdown should be closed.

This is actually very spot on. My concern is that while using Turbolinks disconnect method was used in order to have a single and final spot where your controller would shape page's state, before it was cached. Before Turbo-v.7.0.0.beta4 it was definitely not the case for me.. But after this release my experience has improved vastly regarding this issue.

From your answers i have come to conclusion that the issue still persists even while using the main branch of Turbo. If my assumption is correct, i should keep my issue open at Turbo's repository.. if not i am gonna close it. Thanks in advance.

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024

Hi @thanosbellos,

For the issue I have outlined in this ticket, I came to the conclusion that the fix should be part of tailwindcss-stimulus-components rather than Turbo. Upon selecting an option in the dropdown, tailwindcss-stimulus-components should be responsible for closing the dropdown. This tends to happen naturally, as the links in the dropdown take the user to another screen, and traditionally, that would fully reload the page, thus the dropdown is closed upon rendering the new page.

Another way to think about this without involving Turbo. If one of the links in the dropdown was used to call a JavaScript function (e.g toggle light/dark mode) without navigating the user away from the page, upon click, I would expect the dropdown menu to close. This would not happen at the moment.

As a consequence of the dropdown being left open, this is the state which is captured by Turbo upon snapshoting as outlined in the issue above.

By tailwindcss-stimulus-components ensuring that the dropdown state is updated accordingly via one of the two methods outlined in #63 (comment), the dropdown is left in the correct state for Turbo to cached, thus using the back button presents the dropdown as expected.

However, all that said, I was expecting to be able to add this.hide() to the controllers disconnect method to achieve the same effect, albeit this approach would not cater for the JavaScript light/dark mode example above and this is why the responsible should lie with tailwindcss-stimulus-components.

So I'm pretty certain that Turbo is working slightly different to Turbolinks. If you look add the diagrams added on turbolinks/turbolinks#390

Screenshot 2021-03-12 at 16 39 24

Turbolinks was updated to ensure the snapshot was saved to the cache after the controller's disconnect method has been called (I haven't tested the issue outlined on this thread using Turbolinks). I found that this was not happening in Turbo(v.7.0.0.beta4) or in the pull requests mentioned in (hotwired/turbo#117). However, it's worth noting that my dropdown was using the animations as outlined at https://github.com/excid3/tailwindcss-stimulus-components#dropdowns e.g:

data-dropdown-invisible-class="opacity-0 scale-95"
data-dropdown-visible-class="opacity-100 scale-100"
data-dropdown-entering-class="ease-out duration-300"
data-dropdown-enter-timeout="300"
data-dropdown-leaving-class="ease-in duration-300"
data-dropdown-leave-timeout="300"

So perhaps Turbo is calling controller#disconnect and before the animation to close the dropdown had finished, Turbo snapshots the page, thus the dropdown appearing open upon return. Would it be helpful for me to test this theory, by removing the animation (and adding some debug output into Turbo)?

from tailwindcss-stimulus-components.

thanosbellos avatar thanosbellos commented on June 16, 2024

Thank you very much for your time and for your detailed response.

Hi @thanosbellos,
For the issue I have outlined in this ticket, I came to the conclusion that the fix should be part of tailwindcss-stimulus-components rather than Turbo. Upon selecting an option in the dropdown, tailwindcss-stimulus-components should be responsible for closing the dropdown. This tends to happen naturally, as the links in the dropdown take the user to another screen, and traditionally, that would fully reload the page, thus the dropdown is closed upon rendering the new page.
Another way to think about this without involving Turbo. If one of the links in the dropdown was used to call a JavaScript function (e.g toggle light/dark mode) without navigating the user away from the page, upon click, I would expect the dropdown menu to close. This would not happen at the moment.
As a consequence of the dropdown being left open, this is the state which is captured by Turbo upon snapshoting as outlined in the issue above.
By tailwindcss-stimulus-components ensuring that the dropdown state is updated accordingly via one of the two methods outlined in #63 (comment), the dropdown is left in the correct state for Turbo to cached, thus using the back button presents the dropdown as expected.

Definitely on board with this approach.. It's really logical to handle both the cases you described at will. i.e someone may want to find the dropdown open after pressing back button.

However, all that said, I was expecting to be able to add this.hide() to the controllers disconnect method to achieve the same effect, albeit this approach would not cater for the JavaScript light/dark mode example above and this is why the responsible should lie with tailwindcss-stimulus-components.

This is what caught my attention. That, regardless the desired intention and how it could be achieved by the library:

  1. you would like to manipulate dom before caching
  2. you expected that if you did so from the disconnect method
  3. you expected the cached page would be the result of the manipulation.
    just like it was happening using turbolinks after the (turbolinks/turbolinks#390)

However, it's worth noting that my dropdown was using the animations as outlined at https://github.com/excid3/tailwindcss-stimulus-components#dropdowns e.g:
data-dropdown-invisible-class="opacity-0 scale-95"
data-dropdown-visible-class="opacity-100 scale-100"
data-dropdown-entering-class="ease-out duration-300"
data-dropdown-enter-timeout="300"
data-dropdown-leaving-class="ease-in duration-300"
data-dropdown-leave-timeout="300"
So perhaps Turbo is calling controller#disconnect and before the animation to close the dropdown had finished, Turbo snapshots the page, thus the dropdown appearing open upon return. Would it be helpful for me to test this theory, by removing the animation (and adding some debug output into Turbo)?

If you have the time i would be really grateful if you tried that scenario(no animations). I will proceed and test it using turbolinks.

from tailwindcss-stimulus-components.

thanosbellos avatar thanosbellos commented on June 16, 2024

Using "@hotwired/turbo-rails": "^7.0.0-beta.5" defined via the package.json, the output is as follows:

Would you like me to test against Turbo's main branch? Did you find an easy way to do this? I have both turbo-rails and turbo checked out locally. I'm assuming the easiest way is to copy the relevant files into my project's node_modules/@hotwired/turbo/dist/ (and node_modules/@hotwired/turbo-rails/app/assets/javascripts/turbo.js)?

Yeah i use turbo-rails too. i didn't dig up more about a better way to test it out.. that's how i test it too. i just created a new project to test it out with turbolinks. If you have the time and you are in the mood you can proceed with your tests 😄 But you have helped a lot so don't feel obliged to do so :) I will report my finding back soon (i guess)

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024

The turbo:before-cache is clearly happening before the DropdownController#disconnect is called.

That said, in the 'after' diagram on turbolinks/turbolinks#390, turbo:before-cache is called before the controller's disconnect, but the snapshot'ing is deferred until after the controller's disconnect:

Screenshot 2021-03-12 at 16 39 24

by deferring caching, it’s now possible for Stimulus controllers (and other code which uses MutationObserver) to prepare elements for caching in response to mutation records.

So the log output above is as expected I guess!

from tailwindcss-stimulus-components.

thanosbellos avatar thanosbellos commented on June 16, 2024

Exactly. I guess that their goal is to maintain the same behaviour in Turbo too.. It makes perfect sense to have your controller's disconnect method, to reset external libraries(i.e uppy file uploader, lightbox, flatpickr).

What seems to be happening is that sometimes, if you manipulate the dom inside the disconnect method, the snapshot cache does not contain the changes. All of my custom controllers suffered from the issue before v.7.0.0.beta4.

I only have one controller now that still has the same issue.. although it didn't work well with turbolinks neither.. that's why i was about to close the issue and then i saw your use case.

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024

I've removed Turbo (and Turbo-rails) and switched the project back to "turbolinks": "^5.2.0". The same issue occurs when using the back button, i.e. the drop-down is still open. If I add this.hide() the tailwindcss-stimulus-components dropdown controller disconnect method, it's working exactly the same as the 2nd video in #63 (comment) i.e. click back, the page is displayed, then the hide occurs.

In summary, it seems like Turbo is working the same as Turbolinks, but it is not how I was expecting it to work based upon turbolinks/turbolinks#390

It’s natural to expect to be able to “tear down” a controller’s element in a Stimulus disconnect() callback, but under the current rendering process, any changes to the element are ignored since the callback happens after the document has been cached by Turbolinks.

In the revised rendering process, Turbolinks defers snapshot caching using a setTimeout callback, moving the expensive cloneNode() operation outside of the animation frame.

Additionally, by deferring caching, it’s now possible for Stimulus controllers (and other code which uses MutationObserver) to prepare elements for caching in response to mutation records.


For completeness, here's the output using Turbolinks:

Initial page load:

DropdownController#connect
turbolinks:load

Click a link in the dropdown (or simply navigate to another page)

turbolinks:click
turbolinks:before-visit
turbolinks:request-start
turbolinks:visit
turbolinks:request-end
turbolinks:before-cache
turbolinks:before-render
turbolinks:render
turbolinks:load
DropdownController#disconnect
DropdownController#connect

from tailwindcss-stimulus-components.

thanosbellos avatar thanosbellos commented on June 16, 2024

Yeap tested it on new project and it seems to behave like what you have described on both occasions. Even without animations i see the menu closing rapidly after restoring from the cache. But it does close something that is crucial in general. As long as it has the same behaviour, i am gonna close it for now and maybe we start a new issue about whether the "expected" functionality could be achieved. Thanks a lot for your time and contribution.

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024

Even without animations i see the menu closing rapidly after restoring from the cache. But it does close something that is crucial in general.

Just to confirm, this doesn't happen when using tailwindcss-stimulus-components by default, the dropdown is always open after restoring from the cache?

Once this.hide() is added to the tailwindcss-stimulus-components dropdown controller disconnect method, I experience what you have described:

the menu closing rapidly after restoring from the cache.

from tailwindcss-stimulus-components.

davegudge avatar davegudge commented on June 16, 2024

I will close this issue as I have opened #65 which resolves the problem outlined above.

from tailwindcss-stimulus-components.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.