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

J'ai rencontré un problème dans mon application Rails 4 en essayant d'organiser les fichiers JS "le chemin des rails". Ils étaient précédemment dispersés sur différentes vues. Je les ai organisées en fichiers distincts et compilez-les avec le pipeline d'actifs. Cependant, je viens d'apprendre que l'événement «prêt» de jQuery ne déclenche pas les clics suivants lorsque la turbo-liaison 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 du ready( function($) { ne sera pas exécuté (car la page ne se recharge pas encore). Bonne explication: ici .

Donc, ma question est la suivante: quelle est la bonne façon de s'assurer que les événements jQuery fonctionnent correctement pendant que les turbo-liens sont activés? Enroulez-vous les scripts dans un auditeur spécifique aux Rails? Ou peut-être que les rails ont une certaine magie qui le rend inutile? Les documents sont un peu vagues sur la façon dont cela devrait fonctionner, surtout en ce qui concerne le chargement de plusieurs fichiers via le (s) manifeste (s) comme application.js.

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 que les liens turbo déclencheront.

Modifier … en ajoutant 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ée lors de la charge initiale. Nous pouvons donc faire ce qui suit:

 $(document).on('turbolinks:load', function() { ...your javascript goes here... }); 

Je viens d'apprendre une autre option pour résoudre ce problème. Si vous chargez le joyau jquery-turbolinks 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 venez d'ajouter jquery.turbolinks juste après jquery dans le fichier js manifeste (par défaut: application.js ).

Récemment, j'ai trouvé la façon la plus propre et la plus facile de comprendre:

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

OU

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

MODIFIER
Si vous avez délégué des événements liés au document , assurez-vous de les attacher en dehors de la fonction ready , sinon ils obtiendront un rebond sur chaque page:load événement (entraînant que les mêmes fonctions soient exécutées plusieurs fois). Par exemple, si vous avez des appels comme ceci:

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

Retirez-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 au document n'ont pas besoin d'être liés à l'événement ready .

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

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

OU

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

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

Selon les guides des nouveaux rails , la bonne façon est de faire ce qui suit:

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

Ou, dans 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 joyau jquery.turbolinks .

Cela fonctionne avec les rails 4.2 et plus, non seulement les rails 5.

REMARQUE: voir la réponse de @ SDP pour une solution intégrée et intégrée

Je l'ai réparé comme suit:

Assurez-vous d'inclure application.js avant que les autres fichiers dépendants de l'application ne soient inclus en modifiant l'ordre d'achat comme suit:

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

Définissez 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'); }); 

Aucun des éléments ci-dessus ne fonctionne pour moi, j'ai résolu cela en n'utilisant pas jQuery's $ (document) .ready, mais utilisez addEventListener à la place.

 document.addEventListener("turbolinks:load", function() { // do something }); 

Je pensais que je laisserais cela ici pour ces mises à niveau vers Turbolinks 5 : la façon la 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

Au lieu d'utiliser une variable pour enregistrer la fonction "prête" et l'associer aux événements, vous voudrez peut-être déclencher l'événement ready chaque fois que la page:load déclencheurs.

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

Voici ce que j'ai fait pour s'assurer que les choses ne sont 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 en utilisant $(document).on("page:change") se comporte elle-même de manière inattendue, – surtout si vous êtes en développement.

J'ai trouvé l' article suivant qui a 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) 
 $(document).ready(ready) $(document).on('turbolinks:load', ready) 

Utilisez soit 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

  <%= link_to 'Edit', edit_article_path(article), 'data-no-turbolink' => true %> 

Peut-être que vous pouvez utiliser comme ceci pour utiliser "prêt", il suffit de fermer votre turbolink.

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

Comme décrit ici , si vous avez mis 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 pour qu'il soit chargé avant le contenu de la balise. Cette solution a fonctionné pour moi.

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); 

Vous devez utiliser:

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

À partir de turbolinks doc .