I've tried to find a solution to this error but with no luck so I'll post my specific problem. I have a jquery scroll that scrolls to the hashtags in the menu and when reached the specific target hashtags it should change the menu item color from grey to white. Everything works fine with one small error.
When you click on the menu item it scrolls down but then you have to scroll 1-5px more in order for the script to change the menu item to active (white color), the console also gives me a "cannot read property 'top' of undefined. Im clueless because the script gathers the menu items in an array and if I console.log the array the items are there. If I console.log the height and position of the div it returns values but still gives me the error messages.
<div class="header">
<div id="nav-anchor"></div>
<div class="container-fluid menu-content">
<div class="row">
<div class="col-md-6">
<img src="images/logotype.png" alt="Logotype" title="" class="brand">
</div><!-- end col md 6 brand -->
<div class="col-md-6 menu">
<nav>
<ul>
<li>About</li>
<li>Work</li>
<li>Cases</li>
<li>Meet us</li>
<li>Follow us</li>
</ul>
</nav>
</div><!-- end col md 6 menu -->
</div><!-- end row -->
</div><!-- end container -->
</div><!-- end header -->
$(document).ready(function(){
/**
* This part does the "fixed navigation after scroll" functionality
* We use the jQuery function scroll() to recalculate our variables as the
* page is scrolled/
*/
$(window).scroll(function(){
var window_top = $(window).scrollTop(); // the "12" should equal the margin-top value for nav.stick
var div_top = $('.header').offset().top;
});
/**
* This part causes smooth scrolling using scrollto.js
* We target all a tags inside the nav, and apply the scrollto.js to it.
*/
$(".menu li a").click(function(evn){
evn.preventDefault();
$('html,body').scrollTo(this.hash, this.hash);
if (window_top > div_top) {
$('nav').addClass('stick');
} else {
$('nav').removeClass('stick');
}
});
/**
* This part handles the highlighting functionality.
* We use the scroll functionality again, some array creation and
* manipulation, class adding and class removing, and conditional testing
*/
var aChildren = $("nav li").children(); // find the a children of the list items
var aArray = []; // create the empty aArray
for (var i=0; i < aChildren.length; i++) {
var aChild = aChildren[i];
var ahref = $(aChild).attr('href');
aArray.push(ahref);
} // this for loop fills the aArray with attribute href values
$(window).scroll(function(){
var windowPos = $(window).scrollTop(); // get the offset of the window from the top of page
var windowHeight = $(window).height(); // get the height of the window
var docHeight = $(document).height();
for (var i=0; i < aArray.length; i++) {
var theID = aArray[i];
var divPos = $(theID).offset().top; // get the offset of the div from the top of page
var divHeight = $(theID).height(); // get the height of the div in question
if (windowPos >= divPos && windowPos < (divPos + divHeight)) {
$("a[href='" + theID + "']").addClass("active");
} else {
$("a[href='" + theID + "']").removeClass("active");
}
}
if(windowPos + windowHeight == docHeight) {
if (!$("nav li:last-child a").hasClass("active")) {
var navActiveCurrent = $(".active").attr("href");
$("a[href='" + navActiveCurrent + "']").removeClass("active");
$("nav li:last-child a").addClass("active");
}
}
});
});
window_top needs to be a global variable, also you can add the specified amount of pixels you need to the actual variable so var div_top = $('.header').offset().top + 5;
Related
I'm trying to change active when scrolling in nav bar but it's doesn't work with my code
Here, this is my js code
<script>
let navbar = document.getElementById("nav ul li");
let viewportHeight = window.innerHeight;
let navHeight = document.getElementById("nav ul li").offsetHeight;
let navbarLinks = document.querySelectorAll("nav ul li a");
window.addEventListener("scroll", e => {
scrollpos = window.scrollY;
navbarLinks.forEach(link => {
let section = document.querySelector(link.hash);
if (section.offsetTop <= scrollpos + 20 &&
section.offsetTop + section.offsetHeight > scrollpos + 20) {
link.classList.add("active");
} else {
link.classList.remove("active");
}
});
});
</script>
Here, this is my html code
<nav>
<div class="header">Profile</div>
<ul class="nav-links">
<li>About</li>
<li>Social</li>
<li>MyWorks</li>
<li>Development</li>
<li>Encouragement</li>
<li>Technique</li>
</ul>
</nav>
Ok,
I think you should use document.querySelectorAll(...) instead of document.getElementById(...), (line 2 & 4)
because you are using a CSS QUERY SELECTOR. you should use getElementById only when you are selecting an element by it's id.
I have created simple scroll animation page, if I scroll right side want to delete previous items
then if I scroll left side want to delete next items. see this bellow image, how to solve this issues. could you please solve this issue.
// Sticky Catergory Menu
if ($(window).scrollTop() > 400) {
$("#stickyMenu").addClass('sticky');
} else {
$("#stickyMenu").removeClass('sticky');
}
//get current sroll position
var scrollPosition = $(window).scrollTop();
//get the position of the containers
for (i = 0; i < span_list.length; i++) {
if (scrollPosition >= ($("#" + span_list[i]).offset().top) - 50) {
$("#nav" + (i + 1)).siblings().removeClass("active");
$("#nav" + (i + 1)).addClass("active");
}
}
// if (("div.item:visible")) {
// if ($("div.item").is(":visible")) {
// var content = $(this).html()
// console.log("content == " + content)
// var row_id = $(this).parent().closest("div[id]").attr("id");
// console.log("row_id == " + row_id)
// }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="topnav sticky" id="stickyMenu">
<span data-id="appetizers" id="nav1" class="cat-nav">Appetizers</span>
<span data-id="desserts" id="nav2" class="cat-nav">Desserts</span>
<span data-id="pizza--classic-11-inches-" id="nav3" class="cat-nav active">Pizza (Classic 11 inches)</span>
<span data-id="salad" id="nav4" class="cat-nav">Salad</span><span data-id="soups" id="nav5" class="cat-nav">Soups</span>
<span data-id="thai-noodles" id="nav6" class="cat-nav">Thai Noodles</span>
</div>
I am trying to implement some code I found on SO which adds the class "active" when the matching div is on the page. So scroll down, get to the div and the active class is added to the correct menu item.
Currently, it is working but with some hitches, right now it's applying the active class at the bottom of the div, not when it hits the top. So I think I am at a bit of a loss.
Here is the current JS:
<script>
// Cache selectors
var lastId,
topMenu = $("#nav"),
topMenuHeight = topMenu.outerHeight()+15,
// All list items
menuItems = topMenu.find("a"),
// Anchors corresponding to menu items
scrollItems = menuItems.map(function(){
var item = $($(this).attr("href"));
if (item.length) { return item; }
});
// Bind click handler to menu items
// so we can get a fancy scroll animation
menuItems.click(function(e){
var href = $(this).attr("href"),
offsetTop = href === "#" ? 0 : $(href).offset().top-topMenuHeight+1;
$('html, body').stop().animate({
scrollTop: offsetTop
}, 300);
e.preventDefault();
});
// Bind to scroll
$(window).scroll(function(){
// Get container scroll position
var fromTop = $(this).scrollTop()+topMenuHeight;
// Get id of current scroll item
var cur = scrollItems.map(function(){
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length-1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
// Set/remove active class
menuItems
.parent().removeClass("active")
.end().filter("[href='#"+id+"']").parent().addClass("active");
}
});
</script>
You can view the original js here on jsfiddle but mine is not acting like this one: http://jsfiddle.net/mekwall/up4nu/
The issue I see: on fiddle it works but the divs on fiddle have no height just a top value, if you add height like any div would have it causes the issue.
Found a far better solution to what I had above and I made a codepen for it.
https://codepen.io/LukeD1uk/pen/MVeGQW
$(window).scroll(function() {
var windscroll = $(window).scrollTop();
if (windscroll >= 100) {
$('section').each(function(i) {
if ($(this).position().top <= windscroll - 0) {
$('nav li.active').removeClass('active');
$('nav li').eq(i).addClass('active');
}
});
} else {
$('nav li.active').removeClass('active');
$('nav li:first').addClass('active');
}
}).scroll();
I've been using this code snippet to add in a vertical dot nav to a one page site, which smooth scrolls to a section when one of the links are clicked, and keeps a highlight on the active section. I did a lot of tweaking to the css to make it look how I wanted, and then replaced the sections.
So this is my code in a jsfiddle, and the main issue I am having is the active class not changing properly, and making the side nav bar mess up. I've posted the JS below.
$(document).ready(function(){
$('.awesome-tooltip').tooltip({
placement: 'left'
});
$(window).bind('scroll',function(e){
dotnavigation();
});
function dotnavigation(){
var numSections = $('section').length;
$('#side-nav li a').removeClass('active').parent('li').removeClass('active');
$('section').each(function(i,item){
var ele = $(item), nextTop;
console.log(ele.next().html());
if (typeof ele.next().offset() != "undefined") {
nextTop = ele.next().offset().top;
}
else {
nextTop = $(document).height();
}
if (ele.offset() !== null) {
thisTop = ele.offset().top - ((nextTop - ele.offset().top) / numSections);
}
else {
thisTop = 0;
}
var docTop = $(document).scrollTop();
if(docTop >= thisTop && (docTop < nextTop)){
$('#side-nav li').eq(i).addClass('active');
}
});
}
/* get clicks working */
$('#side-nav li').click(function(){
var id = $(this).find('a').attr("href"),
posi,
ele,
padding = 0;
ele = $(id);
posi = ($(ele).offset()||0).top - padding;
$('html, body').animate({scrollTop:posi}, 'slow');
return false;
});
It works fairly well on the jsfiddle, but I am putting this code into squarespace, and on there it ends up like this where all of the buttons highlight when you try to change active classes.
I have tried to isolate the bug by going through the html, css, and the js, but I don't have enough knowledge of JS to be able to edit the script to fix it.
I would really appreciate any help. Thanks in advance.
EDIT: Link to broken squarespace
In the code snippet, the sample page is designed with continuous sections, so the method ele.next() will return next sections. In your squarespace page, the sections is not continuous, so method ele.next() will return empty and the code is not working.
Your could try to modify function dotnavigation like this
function dotnavigation(){
var numSections = $('section').length;
$('#side-nav li a').removeClass('active').parent('li').removeClass('active');
var sections = $('section');
var i = 0;
for (i = 0; i < sections.length; i++) {
var ele = $(sections[i]), nextTop;
//console.log(ele.next().html());
if (i < sections.length - 1) {
nextTop = $(sections[i + 1]).offset().top;
}
else {
nextTop = $(document).height();
}
if (ele.offset() !== null) {
thisTop = ele.offset().top - ((nextTop - ele.offset().top) / numSections);
}
else {
thisTop = 0;
}
var docTop = $(document).scrollTop();
console.log(thisTop);
if(docTop >= thisTop && (docTop < nextTop)){
$('#side-nav li').eq(i).addClass('active');
}
}
}
I've updated your code sample here.
I use jQuery to implement the slide show animation.
The html looks like:
<div class="slideshow pointer">
<img class="next" src="img1">
...
</div>
I use jQuery to find the next image, fadeOut the previous one and fadeIn the next one. This slideshow part is made visible by a click action of a image thumb. When the first image is loaded, the webpage will scroll to the right place (a proper position to show the image).
But when I click to show the next image, the webpage scroll to a different place, and click next, the webpage scroll to a second different place. The address stays at 'www.xxx.home.html#/books/01/'. And I use another javascript function to make this address display the webpage at the right position.
I have checked that when I click to show next image, there is only this function used, no other function that would cause a slideDown or scroll action (not 100% sure). I am wondering if fadeIn() action does something more than I expect, e.g. some scroll action?
The javascript code:
$('body').on('click', '.slideshow img', function(e){
var thisimg = $(this);
var thisss = thisimg.parent();
var totimgs = thisss.find("img").length;
if (totimgs > 1){
var thisindex = thisimg.index();
var x = e.pageX - 240;
if (x < 240 || x > 600) {
if (x < 240) {
var nextindex = thisindex - 1;
if (nextindex < 0) {
nextindex = totimgs - 1;
}
} else if (x > 600) {
var nextindex = thisindex + 1;
if (nextindex > totimgs - 1) {
nextindex = 0;
}
} else {
nextindex = thisindex;
}
thisimg.fadeOut(500);
var nextss = thisss.find("img:nth-child(" + (nextindex + 1) + ")");
nextss.fadeIn(500);
}
}
});
Can anyone give the reason why? Or there is something else I need to check what makes this scroll?