Home > database >  Uncaught TypeError: Cannot read properties of undefined (reading 'className') at HTMLDivEl
Uncaught TypeError: Cannot read properties of undefined (reading 'className') at HTMLDivEl

Time:07-09

Click here to see the image I am new to javascript. I am trying to switch between the sections and I am getting a TypeError. Don't know what to do.

const sections = document.querySelectorAll('.section');
const sectBtns  = document.querySelectorAll('.controls');  
const sectBtn = document.querySelectorAll('.control');     
const allSections = document.querySelector('.main-content');  


function PageTransition() {
    //Button click active class
    for(let i = 0; i < sectBtn.length; i  ) {
        sectBtn[i].addEventListener('click', function(){
            let currentBtn = document.querySelectorAll('.active-btn');
           
            currentBtn[0].className = 
            currentBtn[0].className.replace('active-btn', '');

            this.className  = 'active-btn';
        })
    }
}

And here's my HTML code. I have element with the class name active-btn.

<body >
    <header >

    </header>    

    <main>
        <section ></section>
        <section ></section>
        <section ></section>
        <section ></section>
    </main>
    
    <div >
        <div >
            <i ></i>
        </div>
        <div  data-id="about">
            <i ></i>
        </div>
        <div  data-id="portfolio">
            <i ></i>
        </div>
        <div  data-id="skills">
            <i ></i>
        </div>
        <div  data-id="contact">
            <i ></i>
        </div>
           
    </div>

<script src="app.js"></script>
</body>

CodePudding user response:

The first time you try to get the active button, there aren't any elements with that class, so document.querySelectorAll just returns an empty array.

Then, when you try to access the first element, that returns undefined.

What causes the error is trying to access className on that undefined.

You can fix that by using optional chaining, so it only accesses the property if there's an element.

for(let i = 0; i < sectBtn.length; i  ) {
    sectBtn[i].addEventListener('click', function(){
        //                       (1)
        let currentBtn = document.querySelector('.active-btn');

        //        (2)    (3)  (4)
        currentBtn?.classList.remove('active-btn');

        this.classList.add('active-btn')
    })
}
  1. I changed this to querySelector instead of querySelectorAll because you are only looking for the first result.

  2. This is the optional chaining. If currentBtn is null or undefined, then nothing will happen (no error).

    If it isn't null or undefined, then the active-btn class will be removed.

  3. This is changed to classList instead of className, because classList has a better API.

  4. This is how you remove a class with classList. If you want to read more about it, this is the MDN link.

I hope this helps! :)

  • Related