Làm việc với turbo link 5

Tại sao lại sử dụng turbo link ?

Turbolinks khiến bạn chuyển trang trong ứng dụng của bạn nhanh hơn. Bằng cách fetch html page từ server, thay thế body bằng body mới và (merge thẻ head). Điều này đồng nghĩa với việc code javascript sẽ không cần phải chạy lại vì trước đó đã có các thẻ script trong head và được chạy rồi.

Cách cài đặt

mặc định rails đã implement turbolink. Nếu chưa bạn có thể cài đặt theo link, https://github.com/turbolinks/turbolinks

Tác dụng to lớn là vậy nhưng những người mới làm quen với javascript như mình rất hay gặp phải các vấn đề khi Làm việc với turbo link 5

Các vấn đề thường gặp

1. Không bắt được sự kiện của element

ví dụ:

$(".avatar_change").click(function(){
  console.log("fired");
});

Hiện tượng:

Mặc dù đã khai báo sự kiện như vậy nhưng khi click vào element có class="avatar_change" vẫn không thấy console hiện log.

Nguyên nhân:

Do khi đọan code khai báo sự kiện được chạy thì Document vẫn chưa load xong nên không có element thỏa mãn điều kiện nên hàm khai báo sự kiện không có ý nghĩa.

Giải pháp:

$(document).ready(function(){
  $(".avatar_change").click(function(){
    console.log("fired");
  });
});

-Bọc vào $(document).ready() được không?, mục đích là đợi đến khi document load xong, lúc đó có các element class="avatar_change" nên sự kiện được khai báo thành công. Quả nhiên, khi click vào element này có thấy console hiện log.

Tuy nhiên vấn đề chưa được giải quyết triệt để, khi chuyển hướng từ 1 trang khác đến trang hiện tại, theo cơ chế của turbo-link $(document).ready() không được gọi, dẫn đến không bắt được sự kiện click và bug vẫn còn.

$(document).on("turbolinks:load", function(){
  $(".avatar_change").click(function(){
    console.log("fired");
  });
});

-Bọc vào $(document).on("turbolinks:load"). Sự kiện này được gọi mỗi khi turbo-link chuyển trang (sau khi render xong html), như vậy event click được khai báo sau khi document có element class="avatar_change" nên vấn đề được giải quyết.

2. Không bắt được sự kiện của element được tạo mới bằng ajax

Dù có khai báo trong $(document).on("turbolinks:load") nhưng với những element được tạo bởi ajax ví dụ:

  var txt = document.createElement("p");
  txt.innerHTML = "Text.";
  $("body").append(txt);

Những element này được thêm vào sau khi khai báo $(".avatar_change").click() nên không thể nhận được sự kiện click().

Giải pháp: gọi lại sau mỗi lần thêm element được không?

  $(".avatar_change").click(function(){
    console.log("fired");
  });

-> Không được, vì sẽ dấn đến duplicate event.

Vậy phải khai báo sự kiện như sau:

  $(document).on("click", ".avatar_change", function(){
    console.log("fired");
  });
});

vì sự kiện được lắng nghe trên $(document) nên dù có chuyển trang hay load ajax cũng đều được.

Lưu ý: các event lắng nghe trên $(document) không đưa vào call_back của event khác ($(document).on("turbolinks:load")...) nếu không sẽ dẫn tới duplicate event.

3. Lỗi liên quan đến phím back trên trình duyệt

Sau khi chuyển hướng trang nhiều lần, logic javascript có thể bị conflic (khi cắm các plug-in không hỗ trợ turbolink), lúc đó có thể yêu cầu turbo-link load lại html từ server về. Nhúng thẻ sau vào trang cần load lại.

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

III. Kết luận

Như vậy, khi khai báo các event bạn nên bọc vào $(document).on("turbolinks:load") Đối với các event trên các element load bằng ajax nên khai báo như sau $(document).on("click", ".avatar_change") (Lưu ý đã khai báo như thế này thì không được bọc vào "turbolinks:load"). Hoặc để cho chắc chắn nên thêm $(document).off("click", ".avatar_change"); để tránh duplicate trong trường hợp có ai đó đã khai báo event này từ trước.

  $(document).off("click", ".avatar_change");
  $(document).on("click", ".avatar_change", function(){
    console.log("fired");
  });
});
Hi vọng các bạn thấy bài viết này hữu ích.

Tham khảo: https://github.com/turbolinks/turbolinks