javascript - Rails 4: hur man använder $ (document).ready() med turbo-länkar


Jag stötte på ett problem i min Rails 4-app när jag försökte organisera JS-filer ”på Rails-sätt”. De var tidigare utspridda över olika vyer. Jag organiserade dem i separata filer och komponerade dem med assets-pipelinen. Men jag lärde mig precis att jQuery:s ”ready”-händelse inte triggas vid efterföljande klick när turbo-linking är på. Första gången du laddar en sida fungerar det. Men när du klickar på en länk kommer ingenting inuti ready( function($) { att köras (eftersom sidan faktiskt inte laddas om). Bra förklaring: här.

Så min fråga är: Vad är rätt sätt att säkerställa att jQuery-händelser fungerar korrekt när turbo-länkar är på? Ska man kapsla in skripten i en Rails-specifik lyssnare? Eller kanske har Rails någon magi som gör det onödigt? Dokumentationen är lite vag om hur detta bör fungera, särskilt när det gäller att ladda flera filer via manifesten som application.js.

Svar #1

Här är vad jag gör... CoffeeScript:

ready = ->

  ...your coffeescript goes here...

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

sista raden lyssnar efter sidladdning vilket är vad turbo links kommer att utlösa.

Redigera...lägger till Javascript-version (enligt begäran):

var ready;
ready = function() {

  ...your javascript goes here...

};

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

Redigera 2...För Rails 5 (Turbolinks 5) blir page:load turbolinks:load och kommer till och med att utlösas vid första laddningen. Så vi kan bara göra följande:

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

  ...your javascript goes here...

});

Svar #2

Jag har precis lärt mig om ett annat alternativ för att lösa detta problem. Om du laddar jquery-turbolinks-gemen kommer den att koppla Rails Turbolinks-händelserna till document.ready-händelserna så att du kan skriva din jQuery på det vanliga sättet. Du lägger bara till jquery.turbolinks direkt efter jquery i js-manifestfilen (som standard: application.js).

Svar #3

Nyligen hittade jag det mest rena och lättförståeliga sättet att hantera det:

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

ELLER

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

REDIGERA
Om du har delegerade händelser bundna till document, se till att du fäster dem utanför ready-funktionen, annars kommer de att binda om vid varje page:load-händelse (vilket gör att samma funktioner körs flera gånger). Till exempel, om du har några anrop som detta:

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

Ta ut dem ur ready-funktionen, så här:

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

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

Delegerade händelser bundna till document behöver inte bindas på ready-händelsen.

Svar #4

Hittade detta i Rails 4-dokumentationen, liknande DemoZluk:s lösning men något kortare:

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

ELLER

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

Om du har externa skript som anropar $ (document).ready() eller om du inte orkar skriva om all din befintliga JavaScript, då låter denna pärla dig fortsätta använda $ (document).ready() med TurboLinks: https://github.com/kossnocorp/jquery.turbolinks

Svar #5

Enligt de nya Rails-guiderna är det korrekta sättet att göra följande:

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

eller, i coffeescript:

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

Lyssna inte på händelsen $ (document).ready och endast en händelse kommer att utlösas. Inga överraskningar, inget behov av att använda jquery.turbolinks-gemet.

Detta fungerar med Rails 4.2 och senare, inte bara Rails 5.

Svar #6

OBS: Se @SDP:s svar för en ren, inbyggd lösning

Jag fixade det på följande sätt:

se till att du inkluderar application.js innan de andra appberoende js-filerna inkluderas genom att ändra inkluderingsordningen enligt följande:

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

Definiera en global funktion som hanterar bindningen i application.js

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

Nu kan du binda saker som:

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

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

Relaterade artiklar