javascriptflickityswup

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?


Solution

  • 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.