Search code examples
javascriptreactjsruntime-errornext.jsstrapi

TypeError: Cannot read property 'classList' of undefined with Image-Slider


I'm currently working on a website where I use Strapi as a CMS and Next.js(React) in Frontend. The site also has an image slider which obviousely contains an image, a headline and a description.

After some time on the website the following error occurs and the slider stops from working or does things like showing all slides really fast one behind the other. What can I do to solve this?

Unhandled Runtime Error TypeError: Canot read property 'classList' of undefined

I've already tried many solutions I found here on StackOverflow, but nothing worked... I am just not able to find the error in my code, which is the following: (/components/image-slider file)

    import ...
const Slider = ({...}) => {

 if (typeof window !== 'undefined') {
    var slides = document.querySelectorAll('.slide');
    var btns = document.querySelectorAll('.btn-navig');
    let currentSlide = 1;
    
    // Javascript for image slider manual navigation
    var manualNav = function(manual){
        slides.forEach((slide) => {
        slide.classList.remove('active');
    
        btns.forEach((btn) => {
            btn.classList.remove('active');
        });
        });
    
        slides[manual].classList.add('active');
        btns[manual].classList.add('active');
    }
    
        btns.forEach((btn, i) => {
        btn.addEventListener("click", () => {
            manualNav(i);
            currentSlide = i;
        });
        });
    
        // // Javascript for image slider autoplay navigation
        var repeat = function(activeClass){
        let active = document.getElementsByClassName('active');
        let i = 1;
    
        var repeater = () => {
            setTimeout(function(){
            [...active].forEach((activeSlide) => {
                activeSlide.classList.remove('active');
            });
    
            slides[i].classList.add('active');
            btns[i].classList.add('active');
            i++;
    
            if(slides.length == i){
            i = 0;
            }
            if(i >= slides.length){
            return;
            }
            repeater();
        }, 10000);
        }
        repeater();
        }
        repeat();
    }

    if (error) {
        return <div>An error occured: {error.message}</div>;
    }
    return (
        <div className="img-slider">
            <div className="slide active">
                <div className="info">
                   // content 
                </div>
            </div>
            <div className="slide">
                <div className="info">
                // content 
                </div>
            </div>
            // further slides
        
            <div className="navigation">
                <div className="btn-navig active"></div>
                <div className="btn-navig"></div>
                <div className="btn-navig"></div>
            </div>
        
        </div>
    );
    };

// axios request ...

export default Slider;

I hope someone can help me with the above mentioned problem. Thanks a lot!


Solution

  • Your first flaw in the code is this one

    var manualNav = function(manual){
        slides.forEach((slide) => {
        slide.classList.remove('active');
    
        btns.forEach((btn) => {
            btn.classList.remove('active');
        });
        });
    
        slides[manual].classList.add('active');
        btns[manual].classList.add('active');
    }
    

    Here, with every new slide of slides[], you start a new btns[] loop.

        btns.forEach((btn) => {
            btn.classList.remove('active');
        });
    

    But this is just unnecessary processing time that gets lost. Do it this way:

    var manualNav = function(manual){
        slides.forEach((slide) => {
            slide.classList.remove('active');
        });
    
        btns.forEach((btn) => {
            btn.classList.remove('active');
        });
        
        slides[manual].classList.add('active');
        btns[manual].classList.add('active');
    }
    

    Your actual problem is this.

    You have 3 div with the class btn-navig but only 2 with the class slide. But in your repeater() you increase i by 1 with every new loop.

     slides[i].classList.add('active');
     btns[i].classList.add('active');
     i++;
    

    With the second iteration you have the following situation:

     slides[2].classList.add('active');  // undefined
     btns[2].classList.add('active'); // value
    

    There is no slides[2] as only slides[0] and slides[1] have values.

    You have to rethink your indexing-approach.