-1

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

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
Ilyris
  • 3
  • 1
  • 5
  • https://stackoverflow.com/questions/24647839/referenceerror-document-is-not-defined-in-plain-javascript – Paulie_D Aug 15 '18 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. – Mhd Alaa Alhaj Aug 15 '18 at 12:22

2 Answers2

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.
Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
  • 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. – Ilyris Aug 15 '18 at 15:48
  • I glad I could help :) Good luck! – Mosh Feu Aug 16 '18 at 05:20
  • @MoshFeu - Wondered why you have also set `document.documentElement.scrollTop > 50`? – Reena Verma Mar 09 '21 at 12:01
  • TBH, I don't remember but probably I didn't change this part from the OP's code. – Mosh Feu Mar 09 '21 at 12:07
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]
}
dcangulo
  • 1,888
  • 1
  • 16
  • 48
DKyleo
  • 806
  • 8
  • 11