glidejs / glide

A dependency-free JavaScript ES6 slider and carousel. It’s lightweight, flexible and fast. Designed to slide. No less, no more
https://glidejs.com
MIT License
7.33k stars 771 forks source link

disabledArrow: CSS Class .glide__arrow--disabled is not set #307

Open dmitrybret opened 5 years ago

dmitrybret commented 5 years ago

For Type: slider in case rewind: false disabledArrow (.glide__arrow--disabled) should be set.

Thanx a lot

rikjacobs1390 commented 5 years ago

I have the same problem.

petervangennip commented 5 years ago

Would be a great addition

nflorentin commented 5 years ago

Same problem

RomkaLTU commented 5 years ago

Any update on this? Looks like a deal-breaker.

omares commented 5 years ago

Hey, i created a PR for this. Take a look at #328

bennol commented 5 years ago

For anyone stumbling over this problem before the PR is merged and the version 3.4.0 is relased:

I wrote a small helper Component, that adds a disabled attribute to the prev/next buttons on the first/last slide.

var ArrowDisabler = function (Glide, Components, Events) {
  return {
    mount() {
      // Only in effect when rewinding is disabled
      if (Glide.settings.rewind) {
        return
      }

      Glide.on(['mount.after', 'run'], () => {
        // Filter out arrows_control
        for (let controlItem of Components.Controls.items) {
          if (controlItem.className !== 'glide__arrows') {
            continue
          }

          // Set left arrow state
          var left = controlItem.querySelector('.glide__arrow--left')
          if (left) {
            if (Glide.index === 0) {
              left.setAttribute('disabled', '') // Disable on first slide
            } else {
              left.removeAttribute('disabled') // Enable on other slides
            }
          }

          // Set right arrow state
          var right = controlItem.querySelector('.glide__arrow--right')
          if (right) {
              if (Glide.index === Components.Sizes.length - Glide.settings.perView) {
                right.setAttribute('disabled', '') // Disable on last slide
              } else {
                right.removeAttribute('disabled') // Disable on other slides
              }
          }
        }
      })
    }
  }
}

Use it like

new Gilde('.glide').mount({ ArrowDisabler })
PezCoder commented 5 years ago

@bennol This was super useful, I hope this was a part of the library as it's a pretty common usecase. A few things in your code, that I tinkered to make it work are:

  1. The classes glide__arrow--right, .glide__arrow--left, 'glide__arrows' doesn't gets added automatically as of v3.3.0. This are not in the documentation anymore: https://glidejs.com/docs/options/#classes & the one with disabledArrow is defined but not being used in the codebase. https://github.com/glidejs/glide/search?q=disabledArrow&unscoped_q=disabledArrow

So the one who is using can replace those with their own custom classes, whatever they might have put on those elements.

  1. When bound is true, this mayn't work, we'll need to add in perView to get the calculation of next arrow right.

Here's the final code I'll be using:

// Modify these according to your controls
const classes = {
  'controls': 'slider-controls',
  'backArrow': 'slider-back',
  'nextArrow': 'slider-next',
};

function ArrowDisabler (Glide, Components) {
  return {
    mount() {
      // Only in effect when rewinding is disabled
      if (Glide.settings.rewind) {
        return
      }

      Glide.on(['mount.after', 'run'], () => {
        // Filter out arrows_control
        for (let controlItem of Components.Controls.items) {
          if (controlItem.className !== classes.controls) {
            continue
          }

          // Set left arrow state
          var left = controlItem.querySelector('.' + classes.backArrow)
          if (left) {
            if (Glide.index === 0) {
              left.setAttribute('disabled', '') // Disable on first slide
            } else {
              left.removeAttribute('disabled') // Enable on other slides
            }
          }

          // Set right arrow state
          var right = controlItem.querySelector('.' + classes.nextArrow)
          if (right) {
            // Glide.index is based on the active slide
            // For bound: true, there will be no empty space & the last slide will never become active
            // Hence add perView to correctly calculate the last slide
            const lastSlideIndex = Glide.settings.bound
              ? Glide.index + (Glide.settings.perView - 1)
              : Glide.index;

            if (lastSlideIndex === Components.Sizes.length - 1) {
              right.setAttribute('disabled', '') // Disable on last slide
            } else {
              right.removeAttribute('disabled') // Disable on other slides
            }
          }
        }
      })
    }
  }
}

export default ArrowDisabler;

Usage like you mentioned:

new Gilde('.glide').mount({ ArrowDisabler })
jaahoo commented 5 years ago

Hi guys, I am not 100% sure but shouldn't be Components.Sizes.length - 1 changed to Components.Sizes.length - Glide.settings.perView ?

praburangki commented 5 years ago

@omares I saw that your PR has been merged. But how come the class is still not applied?

I just dive into the source code, the PR that has been merged was not included in the latest version.

ivarzLV commented 5 years ago

Agree, the problem is still there.

guilhermeocosta commented 4 years ago

Any updates here? It would be great to have this available in the package.

guillaumew commented 4 years ago

Same problem here

mpukit commented 4 years ago

I'm not seeing any disabled class being passed to the first button initially when there is no ability to go back. Is the solution for the now involve a custom helper (as above) to make this work?

jripmeester commented 4 years ago

Bump on this one. This really should be part of the base controls package.

a1402980 commented 4 years ago

Agreed. This really needs to be implemented.

peterdarthur commented 3 years ago

For those who want to also hide any extra bullets that, when clicked, bring in whitespace (bullets are not restricted by the bound option), I followed @PezCoder 's approach and this works nicely along with his. It requires that {bound: true, focusAt: 0}, although that check may not be 100% necessary. Hope it helps someone.

function SlidelessDotDisabler(Glide, Components) {
    return {
        mount() {
            if (Glide.settings.bound && Glide.settings.focusAt === 0) {
                Glide.on(['mount.after', 'run'], function() {
                    for (let controlItem of Components.Controls.items) {
                        if (controlItem.className !== 'glide__bullets') {
                            continue
                        }
                        var slideCount = Components.Html.slides.length;
                        var visibleSlides = Glide.settings.perView;
                        var dotsToShow = slideCount - (visibleSlides - 1);
                        var dots = controlItem.querySelectorAll('.glide__bullet');
                        if (dots) {
                            for (var i = 0; i < dots.length; i++) {
                                if (i > (dotsToShow - 1)) {
                                    dots[i].remove();
                                }
                            }
                        }
                    }
                })
            }
        }
    }
};