Search code examples
jqueryruby-on-railscoffeescriptturbolinks

With turbolinks, jQuery stops working until a hard refresh


I implemented a dynamic select menu thanks to the related RailsCast video. It worked well but now I have to refresh my webpage so that my JQuery code, written in my .coffee script can work.

I read on the internet that people using javascript and who wrote $(document).ready(function()) had to change this part of the code in $(document).bind('pageinit').

The problem is that I don't know how to adapt this to my .coffee file.

I read also about using PJAX but Turbolinks is supposed to do the same job only this kind of problem may happen with Turbolinks.

My Turbolink gem is in my GemFile and it is required in my application.js file.

What shall I write so that I do not have to refresh my webpage in order to have the JQuery code to work directly ?

Here is the code in my .coffee file :

jQuery ->
  $('#test_contrat_id').parent().hide()
  contrats = $('#test_contrat_id').html()

  $('#test_employe_id').change ->
    employe = $('#test_employe_id :selected').text()
    escaped_employe = employe.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1')
    options = $(contrats).filter("optgroup[label='#{escaped_employe}']").html()
    if options
      $('#test_contrat_id').html(options)
      $('#test_contrat_id').parent().show()
    else
      $('#test_contrat_id').empty()
      $('#test_contrat_id').parent().hide()

And here is the code written in my form :

<div class="field">
  <%= f.label :employe_id %><br>
  <%= f.collection_select :employe_id, Employe.order(:nom_employe), :id, :nom_employe, include_blank: true %>
</div>
<div class="field">
  <%= f.label :contrat_id %><br>
  <%= f.grouped_collection_select :contrat_id, Employe.order(:nom_employe), :contrats, :nom_employe, :id, :nom_contrat, include_blank: true%>
</div>

Solution

  • You do not have to use jquery.turbolinks like the other answer states. You just need to wait to run your javascript until Turbolinks triggers the page:load event.

    See bottom of post for update for Turbolinks 5

    $(document).on 'ready page:load', ->
      # granted I don't know the context here, but instead of using javascript to hide something on DOM load, I would use CSS. Look below for that solution.
      $('#test_contrat_id').parent().hide()
    
    
    $(document).on 'change', '#test_employe_id', (e) ->
      contrats = $('#test_contrat_id').html()
      employe = $('#test_employe_id :selected').text()
      escaped_employe = employe.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1')
      options = $(contrats).filter("optgroup[label='#{escaped_employe}']").html()
      if options
        $('#test_contrat_id').html(options)
        $('#test_contrat_id').parent().show()
      else
        $('#test_contrat_id').empty()
        $('#test_contrat_id').parentemploye
    

    For above CSS comment...

    # css file
    .hidden {
      display: none !important;
      visibility: hidden !important;
    }
    
    # add the class .hidden to that element in your view.
    
    # your CoffeeScript will now be
    $(document).on 'change', '#test_employe_id', (e) ->
      contrats = $('#test_contrat_id').html()
      employe = $('#test_employe_id :selected').text()
      escaped_employe = employe.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1')
      options = $(contrats).filter("optgroup[label='#{escaped_employe}']").html()
      if options
        $('#test_contrat_id').html(options)
        $('#test_contrat_id').parent().removeClass('hidden')
      else
        $('#test_contrat_id').empty()
        $('#test_contrat_id').parent().addClass('hidden')
    

    This GitHub thread is very interesting and worth your read about using .hide() and .show().


    Turbolinks 5

    Turbolinks 5 adds their own event listeners, so you no longer need to use ready page:load.

    $(document).on 'turbolinks:load', ->