The following example required the implementation of jQuery slick-carousel for a Ruby on Rails project running with Turbolinks. Turbolinks events have a couple of small unexpected quirks when trying to initialise slick-carousel and other jQuery libraries.
First we need to install our slick-carousel
package; I’m going to use Node Package Manager for this example, but feel free to use whichever package manager you prefer:
npm i --save slick-carousel
Or add the package to your build via CDN - you can read more about slick-carousel here: https://www.npmjs.com/package/slick-carousel
Be sure to import or require the package in your main application.js
(or wherever relevant in your build):
require("slick-carousel");
You can also import slick-carousel base styles:
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
For non-Turbolinks applications we would normally test whether a page has loaded with window.load, and then initialise slick-carousel on our elements. However we need a slightly different approach with Turbolinks; we need to listen for the turbolinks:load event:
document.addEventListener('turbolinks:load', function () {
// Do this
});
In order to initialise slick-carousel we do the following; listen for the turbolinks:load event, target whichever element we want to slick and pass in our configuration object:
document.addEventListener('turbolinks:load', function () {
$(‘.slick-me').slick({
arrows: false,
dots: false,
autoplay: true,
autoplaySpeed: 5000,
touchThreshold: 500,
speed: 300,
waitForAnimate: false,
responsive: [
{
breakpoint: 576,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
}
},
{
breakpoint: 992,
settings: {
slidesToShow: 2,
slidesToScroll: 2,
}
},
{
breakpoint: 1200,
settings: {
slidesToShow: 3,
slidesToScroll: 1,
}
}
]
});
});
It’s as simple as that… sort of. The turbolinks:load event perhaps unexpectedly fires twice when navigating to a new page. Once before the new window has loaded and once after it has loaded.
This causes an issue with initialising slick-carousel on our DOM elements. If a user loads up a page for the first time slick-carousel will correctly initialise on turbolinks:load as it only fires once. However, if a user navigates away from the page with our slick-carousel and then revisits the page by hitting ‘back’ in the browser, slick-carousel will attempt to initialise before the selected element is loaded into the DOM. This may throw a console error in your browser along the lines of:
Uncaught TypeError: Cannot read property 'add' of null
at Slick.initADA (slick.js:1208)
at Slick.init (slick.js:1191)
at new Slick (slick.js:179)
at jQuery.fn.init.$.fn.slick (slick.js:2677)
The way around this is to explicitly unbind any slick-carousels on the page before the window has finished loading. We do this in turbolinks by creating another event listener:
document.addEventListener("turbolinks:before-cache", function () {
const sliders = document.querySelectorAll('.slick-initialized');
sliders.forEach(item => {
$(item).slick('unslick');
})
});
Now, Turbolinks will unbind slick-carousel elements when a user navigates between pages and correctly reinitialises after the window has finished loading.