mkhairi / materialize-sass

Materializecss rubygem for Rails Asset Pipeline / Sprockets
http://materialize.labs.my/
MIT License
805 stars 243 forks source link

Turbolinks crashes when going back and forth in the browser without reloading the page manually! #130

Closed alexventuraio closed 7 years ago

alexventuraio commented 7 years ago

Hi there! As the docs says we need to call an initializer for some JS components like this.

My doubt is, where to put the initializers? because I put it at the end of my form view into a script html tag and it works fine but when I push the browser's back button and then the forward button without refreshing the page, it seems like to render nested JS components into itself. I mean, using the inspector, the html code looks like callbacks in JS.

screen shot 2016-12-15 at 22 30 00

And it increases as many times you go back and forward until you refresh the page.

screen shot 2016-12-15 at 22 27 19

So where to put this JS initializer code in order to be executed only once or maybe how to force the browser to refresh the page on every back and forward action in order to show only one of the components?

This is my code:


<script>
    $(document).ready(function () {
        $('select').material_select();
    });
</script>
oscartzgz commented 7 years ago

If you uses turbolinks you can put the code in assets/application.js like this: $(document).on('turbolinks:load', function() { $('select').material_select(); });

alexventuraio commented 7 years ago

Thanks @oscartzgz I have done what you said but I still getting the same behavior when I go back and forward with out reloading the page. It seems to be creating components on the fly. Even though I'm using turbo links with the turbolinks:load event handler.

mkhairi commented 7 years ago

try

<head>
  ...
  <meta name="turbolinks-cache-control" content="no-preview">
</head>

see https://github.com/turbolinks/turbolinks#opting-out-of-caching

ttrmw commented 7 years ago

Same issue here. I initialize the select as you've indicated, on turbolinks:load, and have tried adding the meta tag but to no effect.

FinnWoelm commented 7 years ago

If you use Turbolinks, you want to destroy the select before the page is cached by calling $('select').material_select('destroy'); (see Updating/Destroying Select in Forms).

The reason is that .material_select() does a bunch of magic to create your beautiful selects. When you navigate away from the page, Turbolinks caches the whole page as is with all the magic. So when you load that page from cache later and run .material_select() again, the magic is applied again and you end up with the nested selects that you have described. So what you want to do is to "undo" the Materialize magic before caching. You can do that by destroying the material select in Turbolink's before-cache hook.

This is written in Coffeescript [so you'll need to convert it](http://coffeescript.org/#try:%23%20app%2Fassets%2Fjavascripts%2Fhelpers%2Fmaterialize.coffee%0A%23%20Make%20sure%20this%20file%20is%20loaded%20on%20every%20page%20load%20(it%20will%20be%20if%20you%20have%20the%20line%20%2F%2F%3D%20require_tree%20.%20in%20app%2Fassets%2Fjavascripts%2Fapplication.js)%0A%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%23%23%20Helper%20file%20to%20make%20Materialize%20work%20with%20Turbolinks%20%23%23%23%23%23%23%0A%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%0A%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%23%23%20ON%20LOAD%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%23%23%20Actions%20to%20be%20executed%20on%20page%20load%20(first%20or%20history)%20%23%23%23%23%0A%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%24(document).on%20%27turbolinks%3Aload%27%2C%20-%3E%0A%0A%20%23%20bunch%20of%20stuff%20here%20(fixing%20tooltips%2C%20datepicker%2C%20etc...)%0A%0A%20%23%20initialize%20selects%0A%20%24(%27select%27).material_select()%0A%0A%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%23%23%20BEFORE%20CACHE%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%23%23%20Actions%20to%20be%20executed%20before%20Turbolinks%20caches%20the%20page%20%23%23%0A%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%0A%24(document).on%20%27turbolinks%3Abefore-cache%27%2C%20-%3E%0A%0A%20%23%20bunch%20of%20stuff%20here%20(fixing%20tooltips%2C%20datepicker%2C%20etc...)%0A%0A%20%23%20destroy%20selects%0A%20%24(%27select%27).material_select(%27destroy%27)%3B), but here is what I do:

# app/assets/javascripts/helpers/materialize.coffee

##############################################################
## Helper file to make Materialize work with Turbolinks ######
##############################################################

##############################################################
## ON LOAD ###################################################
## Actions to be executed on page load (first or history) ####
##############################################################
$(document).on 'turbolinks:load', ->

  # bunch of stuff here (fixing tooltips, datepicker, etc...)

  # initialize selects
  $('select').material_select()

##############################################################
## BEFORE CACHE ##############################################
## Actions to be executed before Turbolinks caches the page ##
##############################################################   
$(document).on 'turbolinks:before-cache', ->

  # bunch of stuff here (fixing tooltips, datepicker, etc...)

  # destroy selects
  $('select').material_select('destroy')

PS: Make sure this file is loaded on every page (it will be if you have the line //= require_tree . in app/assets/javascripts/application.js)

alexventuraio commented 7 years ago

Yes! @fwoelm you're right. It has to see with the JS elements cached when loading pages. But I do something a little bit different and that's how I'm solving the issue right now. With Toast elements I call another method which is actually not included in the Materialize documentation but in the jQuery docs .remove().

So, this is what I'm doing:

$(document).on("turbolinks:before-cache", function () {
    // Destroy cached JS elements on turbolinks 'before-cache' to recreate new ones on 'load' event
    $('select').material_select('destroy');
    $('.toast').remove();
});

I tell jQuery to select all the HTML elements with the toast class and then just remove them.

And it works like a charm! 😃 So, it is solved by the moment!