stimulus-carousel icon indicating copy to clipboard operation
stimulus-carousel copied to clipboard

Reference multiple instances from controller

Open dp6ai opened this issue 3 years ago • 3 comments

Hi,

I've been struggling to work out how to achieve the swiper thumbs navigation like here:

Thumbs

How would i set up multiple carousels and pass the reference of one to the other with stimulus? Like this:

<script>
      var swiper = new Swiper(".mySwiper", {
        spaceBetween: 10,
        slidesPerView: 4,
        freeMode: true,
        watchSlidesProgress: true,
      });
      var swiper2 = new Swiper(".mySwiper2", {
        spaceBetween: 10,
        navigation: {
          nextEl: ".swiper-button-next",
          prevEl: ".swiper-button-prev",
        },
        thumbs: {
          swiper: swiper,
        },
      });
    </script>

dp6ai avatar Sep 20 '21 15:09 dp6ai

Hi,

I think in this case, you should override the controller and do this inside it

guillaumebriday avatar Oct 15 '21 15:10 guillaumebriday

Hi, @guillaumebriday!

is it possible to implement it regularly in your module?

To implement something like https://codepen.io/rogerkuik/pen/abZOLXr, I created a stimulus controller ad_carousel:

import { Controller } from '@hotwired/stimulus'
import Swiper from 'swiper/bundle'

export default class extends Controller {

    connect() {
        let galleryThumbs = new Swiper(".gallery-thumbs", {
            centeredSlides: true,
            centeredSlidesBounds: true,
            direction: "horizontal",
            spaceBetween: 10,
            slidesPerView: 3,
            freeMode: false,
            watchSlidesVisibility: true,
            watchSlidesProgress: true,
            watchOverflow: true,
            breakpoints: {
                480: {
                    direction: "vertical",
                    slidesPerView: 3
                }
            }
        })

        let galleryTop = new Swiper(".gallery-top", {
            direction: "horizontal",
            spaceBetween: 10,
            navigation: {
                nextEl: ".swiper-button-next",
                prevEl: ".swiper-button-prev"
            },
            a11y: {
                prevSlideMessage: "Previous slide",
                nextSlideMessage: "Next slide",
            },
            keyboard: {
                enabled: true,
            },
            thumbs: {
                swiper: galleryThumbs
            }
        })

        galleryTop.on("slideChangeTransitionStart", function () {
            galleryThumbs.slideTo(galleryTop.activeIndex)
        })

        galleryThumbs.on("transitionStart", function () {
            galleryTop.slideTo(galleryThumbs.activeIndex)
        })
    }
}

Placed the following code in the view:

<div class="swiper-container-wrapper" data-controller="ad_carousel">
  <!-- Slider main container -->
  <div class="swiper-container gallery-top">
  ...
</div>

How can this code be improved? Is there any way to override your controller? Create two controllers and somehow use one controller in another via options?

Please show examples. Thank you in advance!

gordienko avatar Feb 26 '23 09:02 gordienko

After small changes:

import {Controller} from '@hotwired/stimulus'
import Swiper from 'swiper/bundle'

export default class extends Controller {
    static targets = ["thumbs", "top"]
    static values = {
        thumbs: Object,
        top: Object
    }

    initialize() {
        this.gallery_thumbs = new Swiper(this.thumbsTarget, {
            ...this.defaultThumbsOptions,
            ...this.thumbsValue
        })

        this.gallery_top = new Swiper(this.topTarget, {
            ...this.defaultTopOptions,
            ...this.topValue
        })
    }

    connect() {
        let galleryTop = this.gallery_top
        let galleryThumbs = this.gallery_thumbs

        galleryTop.on("slideChangeTransitionStart", function () {
            galleryThumbs.slideTo(galleryTop.activeIndex)
        })

        galleryThumbs.on("transitionStart", function () {
            galleryTop.slideTo(galleryThumbs.activeIndex)
        })
    }

    disconnect() {
        this.gallery_thumbs.destroy()
        this.gallery_thumbs = undefined
        this.gallery_top.destroy()
        this.gallery_top = undefined
    }

    get defaultTopOptions() {
        return {
            direction: "horizontal",
            spaceBetween: 10,
            navigation: {
                nextEl: ".swiper-button-next",
                prevEl: ".swiper-button-prev"
            },
            a11y: {
                prevSlideMessage: "Previous slide",
                nextSlideMessage: "Next slide",
            },
            keyboard: {
                enabled: true,
            },
            thumbs: {
                swiper: this.gallery_thumbs
            }
        }
    }

    get defaultThumbsOptions() {
        return {
            centeredSlides: true,
            centeredSlidesBounds: true,
            direction: "horizontal",
            spaceBetween: 10,
            slidesPerView: 3,
            freeMode: false,
            watchSlidesVisibility: true,
            watchSlidesProgress: true,
            watchOverflow: true,
            breakpoints: {
                480: {
                    direction: "vertical",
                    slidesPerView: 3
                }
            }
        }
    }
}

In view:

<div class='swiper-container-wrapper' data-carousel-with-thumbs-thumbs-value='{}' data-carousel-with-thumbs-top-value='{ &quot;a11y&quot;: { &quot;prevSlideMessage&quot;: &quot;Prev&quot;, &quot;nextSlideMessage&quot;: &quot;Next&quot; } }' data-controller='carousel-with-thumbs'>
  <!-- Slider main container -->
  <div class='swiper-container gallery-top' data-carousel-with-thumbs-target='top'>
  <!-- Additional required wrapper -->
  ...
  </div>
</div>

gordienko avatar Feb 26 '23 12:02 gordienko