web-dev-qa-db-fra.com

Rails 4: comment utiliser $ (document) .ready () avec des liens turbo

J'ai rencontré un problème dans mon application Rails 4 en essayant d'organiser les fichiers JS "à la manière Rails". Ils étaient auparavant dispersés à travers différents points de vue. Je les ai organisés en fichiers séparés et les ai compilés avec le pipeline d’actifs. Cependant, je viens d'apprendre que l'événement "prêt" de jQuery ne se déclenche pas lors de clics ultérieurs lorsque la liaison turbo est activée. La première fois que vous chargez une page, cela fonctionne. Mais lorsque vous cliquez sur un lien, tout ce qui se trouve à l'intérieur de la ready( function($) { ne sera pas exécuté (car la page ne se charge plus réellement). Bonne explication: ici .

Ma question est donc la suivante: quel est le bon moyen de s'assurer que les événements jQuery fonctionnent correctement lorsque les liens turbo sont activés? Enroulez-vous les scripts dans un écouteur spécifique à Rails? Ou peut-être que Rails a une magie qui le rend inutile? La documentation est un peu vague sur la façon dont cela devrait fonctionner, en particulier en ce qui concerne le chargement de plusieurs fichiers via le (s) manifeste (s) tel que application.js.

416
emersonthis

Je viens d'apprendre d'une autre option pour résoudre ce problème. Si vous chargez le jquery-turbolinks gem , il liera les événements Rails Turbolinks aux événements document.ready afin que vous puissiez écrire votre jQuery de la manière habituelle. Vous ajoutez simplement jquery.turbolinks juste après jquery dans le fichier de manifeste js (par défaut: application.js).

235
emersonthis

Voici ce que je fais ... CoffeeScript:

ready = ->

  ...your coffeescript goes here...

$(document).ready(ready)
$(document).on('page:load', ready)

la dernière ligne écoute le chargement de la page, ce qui déclenche les liens turbo.

Edit ... ajout de la version Javascript (par demande):

var ready;
ready = function() {

  ...your javascript goes here...

};

$(document).ready(ready);
$(document).on('page:load', ready);

Edit 2 ... Pour Rails 5 (Turbolinks 5) page:load devient turbolinks:load et sera même déclenché lors du chargement initial. Nous pouvons donc simplement faire ce qui suit:

$(document).on('turbolinks:load', function() {

  ...your javascript goes here...

});
549
Meltemi

Récemment, j'ai trouvé le moyen le plus propre et le plus facile à comprendre:

$(document).on 'ready page:load', ->
  # Actions to do

OU

$(document).on('ready page:load', function () {
  // Actions to do
});

EDIT
Si vous avez événements délégués liés à la document, assurez-vous de les attacher en dehors de la fonction ready, sinon ils seront rebondis à chaque page:load event (entraînant l'exécution des mêmes fonctions plusieurs fois). Par exemple, si vous avez des appels comme celui-ci:

$(document).on 'ready page:load', ->
  ...
  $(document).on 'click', '.button', ->
    ...
  ...

Sortez-les de la fonction ready, comme ceci:

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

$(document).on 'click', '.button', ->
  ...

Les événements délégués liés à la document n'ont pas besoin d'être liés à l'événement ready.

201
Artyom Tsoy

Trouvé ceci dans le documentation Rails 4 , similaire à la solution de DemoZluk mais légèrement plus courte:

$(document).on 'page:change', ->
  # Actions to do

OR

$(document).on('page:change', function () {
  // Actions to do
});

Si vous avez des scripts externes qui appellent $(document).ready() ou si vous ne voulez pas réécrire tout votre code JavaScript existant, cette gemme vous permet de continuer à utiliser $(document).ready() avec TurboLinks: https: // github.com/kossnocorp/jquery.turbolinks

91
migu

Comme indiqué dans le nouveau guides Rails , vous devez procéder comme suit:

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

ou, en coffeescript:

$(document).on "turbolinks:load", ->
alert "page has loaded!"

N'écoutez pas l'événement $(document).ready et un seul événement sera déclenché. Pas de surprises, pas besoin d'utiliser le jquery.turbolinks gem.

Cela fonctionne avec Rails 4.2 et versions ultérieures, et pas seulement Rails 5.

78
vedant

NOTE: Voir la réponse de @ SDP pour une solution propre et intégrée

Je l'ai corrigé comme suit:

assurez-vous d'inclure application.js avant l'inclusion des autres fichiers js dépendants de l'application en modifiant l'ordre d'inclusion de la manière suivante:

// in application.js - make sure `require_self` comes before `require_tree .`
//= require_self
//= require_tree .

Définir une fonction globale qui gère la liaison dans application.js

// application.js
window.onLoad = function(callback) {
  // binds ready event and turbolink page:load event
  $(document).ready(callback);
  $(document).on('page:load',callback);
};

Maintenant, vous pouvez lier des choses comme:

// in coffee script:
onLoad ->
  $('a.clickable').click => 
    alert('link clicked!');

// equivalent in javascript:
onLoad(function() {
  $('a.clickable').click(function() {
    alert('link clicked');
});
10
sled

Aucune de ce qui précède ne fonctionne pour moi, j'ai résolu ce problème en n'utilisant pas le $ (document) .ready de jQuery, mais en utilisant addEventListener.

document.addEventListener("turbolinks:load", function() {
  // do something
});
8
RockL
$(document).on 'ready turbolinks:load', ->
  console.log '(document).turbolinks:load'
6
Sukeerthi Adiga

Vous devez utiliser:

document.addEventListener("turbolinks:load", function() {
  // your code here
})

de turbolinks doc .

5

Soit utiliser le

$(document).on "page:load", attachRatingHandler

ou utilisez la fonction .on de jQuery pour obtenir le même effet

$(document).on 'click', 'span.star', attachRatingHandler

voir ici pour plus de détails: http://srbiv.github.io/2013/04/06/Rails-4-my-first-run-in-with-turbolinks.html

3
derekyau

J'ai trouvé ce qui suit article qui a très bien fonctionné pour moi et détaille l'utilisation de ce qui suit:

var load_this_javascript = function() { 
  // do some things 
}
$(document).ready(load_this_javascript)
$(window).bind('page:change', load_this_javascript)
2
Adrian Mann

Au lieu d'utiliser une variable pour enregistrer la fonction "prête" et la lier aux événements, vous pouvez déclencher l'événement ready à chaque fois que page:load se déclenche.

$(document).on('page:load', function() {
  $(document).trigger('ready');
});
2
wachunei

Je pensais que je laisserais ça ici pour ceux qui passent à la version Turbolinks 5 : le moyen le plus simple de réparer votre code est de passer de:

var ready;
ready = function() {
  // Your JS here
}
$(document).ready(ready);
$(document).on('page:load', ready)

à:

var ready;
ready = function() {
  // Your JS here
}
$(document).on('turbolinks:load', ready);

Référence: https://github.com/turbolinks/turbolinks/issues/9#issuecomment-184717346

2
tirdadc

Voici ce que j'ai fait pour que les choses ne soient pas exécutées deux fois:

$(document).on("page:change", function() {
     // ... init things, just do not bind events ...
     $(document).off("page:change");
});

Je trouve que l'utilisation de la gemme jquery-turbolinks ou la combinaison de $(document).ready et $(document).on("page:load") ou de $(document).on("page:change") se comporte de manière inattendue, notamment si vous êtes en développement.

2
Gray Kemmey

Je fais habituellement ce qui suit pour mes Rails 4 projets:

Dans application.js

function onInit(callback){
    $(document).ready(callback);
    $(document).on('page:load', callback);
}

Puis dans le reste des fichiers .js, au lieu d'utiliser $(function (){}) j'appelle onInit(function(){})

1
muZk
$(document).ready(ready)  

$(document).on('turbolinks:load', ready)
1
Konstantinos Mou

Testé tant de solution est finalement venu à cela. Ce code n'est certainement pas appelé deux fois.

      var has_loaded=false;
      var ready = function() {
        if(!has_loaded){
          has_loaded=true;
           
          // YOURJS here
        }
      }

      $(document).ready(ready);
      $(document).bind('page:change', ready);
0
Simon Meyborg

Tout d'abord, installez jquery-turbolinks gem. Et puis, n'oubliez pas de déplacer vos fichiers Javascript inclus de la fin du corps de votre application.html.erb vers son <head>.

Comme décrit ici , si vous avez placé le lien JavaScript de l'application dans le pied de page pour des raisons d'optimisation de la vitesse, vous devrez le déplacer dans la balise de manière à ce qu'il se charge avant le contenu de la balise. Cette solution a fonctionné pour moi.

0
Aboozar Rajabi