Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

only initialise the carousel if there are enough items to (at least) fill the available space #208

Open
bw1984 opened this issue Apr 25, 2018 · 11 comments

Comments

@bw1984
Copy link

bw1984 commented Apr 25, 2018

we have an implementation where our carousels will always have an indeterminate amount of items in and i'd like to be able to have the carousel intelligently initialise/destroy itself depending on whether the amount of items fit within the viewport. Currently if i have a carousel with 1 item in it gets repeated 5 times. Its behaving exactly as i'm telling it to but i just wondered if theres a way to add in some conditional logic so it will automatically decide whether or not to initialise

@jedrzejchalubek
Copy link
Member

jedrzejchalubek commented Apr 25, 2018

It's really hard to tell what you want to archive without some demo. You can simply call mount() method inside a length check.

if (items.length > 5) {
  glide.mount();
}

@bw1984
Copy link
Author

bw1984 commented Apr 27, 2018

your suggestion is sensible but i am struggling to figure out how to reconcile it with responsiveness/breakpoints. I think basically what i'm after is a way to mount and unmount the carousel as part of the breakpoints functionality. To try to give a real world scenario...

  • I have a carousel which happens to have 3 items in (this can differ from view to view)
  • I have the default 'perView' setting set to 5
  • I have a few breakpoints setup for 1200px and 800px
  • at <1200px i want to set perView to 3
  • at <800px i want to set perView to 1

The problem i have is that at sizes above 1200px my 3 items are being repeated, which i dont want, but if i only run mount() conditionally on initial page load (as you suggest) then i miss the opportunity to initialise the breakpoints, which i do want. The only other way i can think of is to implement my own breakpoint observer and run mount/unmount methods manually at varying screen sizes, which would bypass your breakpoints implementation entirely so seems a tad defeatist.

I think being able to mount and unmount at different breakpoints would be nice, although im not sure how that would work within the current implementation. Ultimately the goal is to not have elements (visibly) repeated/duplicated.

I hope this makes sense

@brentkelly
Copy link

brentkelly commented Nov 14, 2018

In case its of any use to anyone I nearly got the following code working. It:

  • detects if there are insufficient slides & injects blank ones to stop duplication
  • disables the slider if there are insufficient slides to do any sliding
  • adds a glide--disabled class if it is disabled so you can control the styling (hiding controls etc)
  • detects when a breakpoint has changed the perView setting & destroys the slider, updates the number of dummy slides as required & recreates.

Unfortunately the destroy API method appears to leak & has memory of previous slides. So when I attempt to refresh the slide deck, it remembers the original slides regardless of the changed state.

I noted there used to be a refresh method - but I can't find one. Surely someone has tried to dynamically changes the slides in their deck before? Is there no way to do this?

Code below:

Glide.prototype._mount = Glide.prototype.mount;
Glide.prototype.mount = function() {

	// if already mounted, destroy
	if (this.mounted) {
		this.destroy();
	}

	// assumes a unique selector
	var element = document.querySelector(this.selector);
	var perView = this.settings.perView;
	var slideParent = element.querySelector('.glide__slides');

	// if there is no need to scroll, hide the controls & disable the slider
	var slideCount = element.querySelectorAll('li.glide__slide').length;
	if (slideCount <= perView) {
		element.classList.add('glide--disabled');
		this.disable();
	} else {
		element.classList.remove('glide--disabled');
		this.enable();
	}

	// add in any missing dummy slides
	for (; slideCount < perView; slideCount++) {
		var dummy = document.createElement('li');
		dummy.className = 'glide__slide glide__slide--dummy';
		slideParent.appendChild(dummy);
	}

	// remount
	this._mount(arguments);
	this.mounted = true;
	
	// store the current perView setting so we know when it's changed & we need to remount
	this.currentPerView = this.settings.perView;
}

// on destroy remove any dummy slides
Glide.prototype._destroy = Glide.prototype.destroy;
Glide.prototype.destroy = function() {
	this._destroy();
	document.querySelectorAll(this.selector + ' li.glide__slide--dummy').
		forEach(function(dummy) {
			dummy.parentNode.removeChild(dummy);
		});
};

// detect when a breakpoint has been hit & remount
var glide = new Glide(selector, settings);
glide.on('resize', function() {
	if (glide.settings.perView != glide.currentPerView) {
		glide.mount();
	}
});
glide.mount();

@matt-bailey
Copy link

Did anyone solve this in the end, I have the same requirement? I have 3 slides. On desktop they should just display in a row, no need to be in a carousel. On mobile however they should 'collapse' into a carousel. I suppose I could basically duplicate my content in the HTML - one block for desktop and one for mobile, and hide/show each block at the relevant breakpoints - but that's obviously not ideal.

@svenbluege
Copy link

My backend code renders a plain list of elements. JavaScript will pick them up and transform them into a slider. This allows me to show a different number of images per slide depending on the screen size. Don't forget that mobile devices have a landscape and a portrait mode.

My code is simple:

  1. check how many images I can fit into one slide
  2. create the slide markup for n slides
  3. fire up GlideJS on this markup

Posting code is a little bit difficult since it is integrated into my application.

@matt-bailey
Copy link

Thanks for the insight @svenbluege. So the way you've approached it is similar to @brentkelly? You're mounting and destroying Glide 'on-the-fly' based on how the slides fit into the current viewport? If there are too many you mount Glide, and if there aren't enough you destroy Glide, is that correct? And presumably you're doing this on window resize as well - constantly checking to see how the slides fit?

@svenbluege
Copy link

@matt-bailey I do not modify GlideJS. I just use it inside my "Slide Transformator". But other than that, you're correct.

@dddeeemmmooonnn
Copy link

my solution

let gallery = document.getElementsByClassName('image-gallery');
if (gallery.length !== 0) {
    let check_resize = (glide) => {
        if (glide.slides_count <= glide.settings.perView) {
            glide.update({startAt: 0}).disable();
        } else {
            glide.enable();
        }
    };
    [...gallery].forEach(el => {
        let el_glide = new Glide(el, {
            gap: 10,
            perView: 4,
            bound: true,
            breakpoints: {
                575: {
                    perView: 1,
                },
                767: {
                    perView: 3,
                },
            }
        });
        el_glide.slides_count = el.querySelectorAll('.glide__slide').length;
        el_glide.on('resize', () => {
            check_resize(el_glide);
        });
        el_glide.mount();
        check_resize(el_glide);
    });
}

@khinkelthein-dotsource
Copy link

my solution

let gallery = document.getElementsByClassName('image-gallery');
if (gallery.length !== 0) {
    let check_resize = (glide) => {
        if (glide.slides_count <= glide.settings.perView) {
            glide.update({startAt: 0}).disable();
        } else {
            glide.enable();
        }
    };
    [...gallery].forEach(el => {
        let el_glide = new Glide(el, {
            gap: 10,
            perView: 4,
            bound: true,
            breakpoints: {
                575: {
                    perView: 1,
                },
                767: {
                    perView: 3,
                },
            }
        });
        el_glide.slides_count = el.querySelectorAll('.glide__slide').length;
        el_glide.on('resize', () => {
            check_resize(el_glide);
        });
        el_glide.mount();
        check_resize(el_glide);
    });
}

Although I would prefer automatic destroy/remount by the plugin itself, your answer helped me for now. Thank you!

@aaronmiller-ehouse
Copy link

This is really high sensitive requirement.. Any updates for this?

@hseager
Copy link

hseager commented Jan 17, 2024

It appears the duplication of items only happens when the Glide type is 'carousel'.

A solution that works in my case is changing the Glide back to a slider if there aren't enough items before the mount:

if (items && items.length < 4) {
   carousel.settings.type = "slider";
}

carousel.mount();

I haven't experimented with this but you can probably do the same in the breakpoint settings:

breakpoints: {
  768: {
    perView: 3,
    type: 'carousel'
  },
  992: {
    perView: 5,
    type: 'slider'
  },
}

Although this isn't ideal as it changes the way Glide behaves, it might be a workaround while a proper fix is considered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants