Skip to content

Flickity & Swup – destroying flickity

I am trying to destroy and re-load my Flickity slideshow while using Swup for page transitions, and I am not having much luck. This is my js file:

import Swup from 'swup';

var Flickity = require('flickity');

function init() {
  if (document.querySelector('.testimonials-slideshow')) {
    var flkty = new Flickity('.testimonials-slideshow', {
      wrapAround: true,
      pageDots: false,
      autoPlay: true,
      arrowShape: 'M68.374,83.866L31.902,50L68.374,16.134L64.814,12.3L24.214,50L64.814,87.7L68.374,83.866Z'
    });
  }
}

function unload() {
  flkty.destroy();
}

init();

const swup = new Swup();

swup.on('contentReplaced', init);

swup.on('willReplaceContent', unload);

But when I try this I get the error flkty is not defined. Can anyone give me any pointers on this?

Answer

Variable scoping

As mentioned by CBroe, your var is undefined because of where you define it. It is defined in a function, but should be defined at the “top level”.

import Swup from 'swup';

var Flickity = require('flickity');

// Added a "global" definition here:
var flkty;

function init() {
  if (document.querySelector('.testimonials-slideshow')) {
    // Removed var:
    flkty = new Flickity('.testimonials-slideshow', {
      wrapAround: true,
      pageDots: false,
      autoPlay: true,
      arrowShape: 'M68.374,83.866L31.902,50L68.374,16.134L64.814,12.3L24.214,50L64.814,87.7L68.374,83.866Z'
    });
  }
}

function unload() {
  flkty.destroy();
}

init();

const swup = new Swup();

swup.on('contentReplaced', init);

swup.on('willReplaceContent', unload);

Furthermore, if you are using any kind of module bundler, sometimes it can still get lost, so you could consider doing something like:

window.flkty = new Flickity('.testimonials-slideshow', ...

And always reference it in that way, i.e.

window.flkty.destroy();

Only destroying instances that exist

That’s it for your variable definition. The next potential error is that you only init flkty when the query selector matches:

if (document.querySelector('.testimonials-slideshow')) {

But you destroy it every willReplaceContent, so really you could do with a check on “is it inited, this page load?”. In this instance, you can do a check like so:

// Init the var as false:
var flkty = false

function init() {
  if (document.querySelector('.testimonials-slideshow')) {
    flkty = new Flickity('.testimonials-slideshow', ...);
  }
}

function unload() {
  if(flkty){
    flkty.destroy();
    // Make sure the flkty var is set to false at the end:
    flkty = false;
  }
}

Neatening up your code

This can all get a bit out of hand, so what we started doing was creating modules. Here is a skeleton of a carousel module we use:

// modules/Carousel.js
import Swiper from "swiper";

export default {
  carouselEl: null,
  carouselSwiper: null,
  setup() {
    this.carouselEl = document.getElementById("header-carousel");
    if (!this.carouselEl) {
      // Just stop if there is no carousel on this page
      return;
    }
    this.carouselSwiper = new Swiper(this.carouselEl, { ... });
    this.carouselSwiper.on("slideChange", () => { ... });
  },
  destroy() {
    // If we already have one:
    if (this.carouselSwiper) {
      this.carouselSwiper.destroy();
    }
    // Make sure we are reset, ready for next time:
    this.carouselSwiper = null;
  },
};

Then, in our main.js we do something like you have:

import Carousel from "./modules/Carousel.js";

function init(){
  Carousel.setup();
  // Add more here as the project grows...
}
function unload(){
  Carousel.unload();
}

swup = new Swup();
swup.on("contentReplaced", init);
swup.on("willReplaceContent", unload);
init();

All of the modules have setup and unload functions that won’t break if the elements don’t exist, so we can call all of them on each page load and unload.

I love swup but also have personal experience in the nightmare of initing and destroying things so let me know if you need any further help.