0

I'm trying to add a className on scroll. I keep getting a

document is undefined

edit: I found out I was getting the error from the typo. When I define document.getElementsByClassName("main-nav").scrollTop nothing comes up in the console. As well as the page does not get affected.

window.onscroll = function() {
  windowScroll();
};

function windowScroll() {
  if (document.getElementsByClassName("main-nav").scrollTop > 50 || document.documentElement.scrollTop > 50) {
    document.getElementsByClassName("main-nav").className = "test";
  } else {
    document.getElementsByClassName("main-nav").className = "";
  }
}

CSS is

.test {
  background: pink
}

I'm not necessarily looking for the answer, I just want guidance

2
  • stackoverflow.com/questions/24647839/… Commented Aug 15, 2018 at 12:03
  • 1
    Since you choose getElementsByClassName so it will get all class names but you want one of them, I suggest you to use jquery it will be much easier than JS. Commented Aug 15, 2018 at 12:22

2 Answers 2

3

There are 2 problems:

getElementsByClassName returns an array of HTMLCollection and it has no property scrollTop. You probably want the first item so the code shoul be document.getElementsByClassName("main-nav")[0] (or document.querySelector(".main-nav"))

But if you try it, you will get an error:

Cannot read property 'scrollTop' of undefined

window.onscroll = function() {
  windowScroll();
};

function windowScroll() {
  if (document.getElementsByClassName("main-nav").scrollTop > 50 || document.documentElement.scrollTop > 50) {
    document.getElementsByClassName("main-nav").className = "test";
  } else {
    document.getElementsByClassName("main-nav").className = "";
  }
}
html, body {
  height: 150%;
}

.test {
  background: pink
}
<div class="main-nav"></div>

The reason is that you override the class attribute of .main-nav by this assignment:

document.getElementsByClassName("main-nav").className = "";

In this line you set the class attribute to empty string. You probably want to add / remove the test call but keeping the main-nav class.

There are 2 things you can do:

  1. Set the id attribute to main-nav instead of the class attribute, then use document.getElementById method.

window.onscroll = function() {
  windowScroll();
};

function windowScroll() {
  if (document.getElementById("main-nav").scrollTop > 50 || document.documentElement.scrollTop > 50) {
    document.getElementById("main-nav").className = "test";
  } else {
    document.getElementById("main-nav").className = "";
  }
}
html, body {
  height: 150%;
}

#main-nav {
  position: fixed;
  width: 100%;
}

.test {
  background: pink
}
<div id="main-nav">Main Nav</div>

  1. Toggle only the test class using classList.toggle.

window.onscroll = function() {
  windowScroll();
};

function windowScroll() {
  if (document.getElementsByClassName("main-nav")[0].scrollTop > 50 || document.documentElement.scrollTop > 50) {
    document.getElementsByClassName("main-nav")[0].classList.add("test");
  } else {
    document.getElementsByClassName("main-nav")[0].classList.remove("test");
  }
}
html, body {
  height: 150%;
}

.main-nav {
  position: fixed;
  width: 100%;
}

.test {
  background: pink
}
<div class="main-nav">Main Nav</div>


The final approach with some optimisations:

var mainNav = document.querySelector('.main-nav');

window.onscroll = function() {
  windowScroll();
};

function windowScroll() {
    mainNav.classList.toggle("test", mainNav.scrollTop > 50 || document.documentElement.scrollTop > 50);
}
html, body {
  height: 150%;
}

.main-nav {
  position: fixed;
  width: 100%;
}

.test {
  background: pink
}
<div class="main-nav">Main Nav</div>

The changes:

  1. Store the .main-nav element on the global context (the window object). It will not change so you don't need to find it in any scroll.
  2. Use querySelector so you will get a single DOM element, not collection.
  3. Use classList.toggle to toggle the class by condition.
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you so much! I'm fairly new at javascript and basically looked at W3 school and tried to use their example with mine without knowing how everyone works with conjunction with each other. Your help + w3 schools made this possible for me. Thank you again.
I glad I could help :) Good luck!
@MoshFeu - Wondered why you have also set document.documentElement.scrollTop > 50?
TBH, I don't remember but probably I didn't change this part from the OP's code.
0

The issue with your console.log is that you're trying to pull the scrollTop for an HTML Collection (a collection of elements in your page) of 1 or more divs - therefore it can't check for the scrollTop as the console.log as it doesn't actually have that property.

Assuming you only have one element with the "main-nav" class (or there is a particular element with this class that you wish to apply it to), you would be better off using one of the following: document.getElementsByClassName("main-nav")[0] or document.getElementById("main-nav") (the latter would require you to create a main-nav id rather than a class).

For the first one, however, using className reassigns the class name rather than adding to that particular div, therefore you can use document.getElementsByClassName("main-nav")[0].classList.add("test") (and remove instead of add if it does not match your criteria).

If there is more than one element with the "main-nav" class, you can still use the first option I suggested - only you would need to wrap it around in a for loop and replace the 0 with your variable of choice.

for (i = 0; i < document.getElementsByClassName("main-nav").length; i++) {
  //your code here using document.getElementsByClassName("main-nav")[i]
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.