Scroll offset changing menu item class - javascript

I have a page in Magento with all the categories and products listed. On top I have a menu with the categories and the items you scroll by must get a class so I can change the color.
I have this script at the moment:
function onScroll(event){
var scrollPos = $(document).scrollTop();
$('ul.nf-category-menu li a').each(function () {
var currLink = $(this);
var refElement = $(currLink.attr("href"));
if (refElement.position().top <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
$('ul.nf-category-menu li a').removeClass("active");
currLink.addClass("active");
}
else{
currLink.removeClass("active");
}
});
}
But the class is changing from div to div to soon, can I give some offset so the class will be added later?
Update:
It's no changing the "active" class to soon when te title is 150px away from the top, I would like to change the class around 80px from top.
Regards,

I already fixed it, it was quite simple after trying some things. This is how it was done:
function onScroll(event){
var scrollPos = $(document).scrollTop();
$('ul.nf-category-menu li a').each(function () {
var currLink = $(this);
var refElement = $(currLink.attr("href"));
if (refElement.position().top+243 <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
$('ul.nf-category-menu li a').removeClass("active");
currLink.addClass("active");
}
else{
currLink.removeClass("active");
}
});
}
if (refElement.position().top had to be changed to: if (refElement.position().top+243 where 243 is the amount of pixels of the offset.

Related

How to auto scroll up li element when the corresponding element is showing using jQuery

I have this HTML page:
https://shibbir.dev/demo-work/html-one-page/
On this page, you will see a second sticky sidebar whose title is "Credit ipotecar"
In this sidebar, I have a few li elements. If you click on any li element you will scroll down to the corresponding div on the right side.
But the problem is I can see only a few li elements on the sidebar thus I can't click on other li elements to see another corresponding div.
So, how can I make the last li element scroll up once I click on the last viewable li element?
Something like this example:
https://discount.ro/cataloage/pepco-ro/cupon-de-reducere-pepco-colectia-de-rochii-din-bumbac-organic-02-15-iunie-2022-16353/#section11
My JS Code:
(function ($) {
"use strict";
$(document).ready(function () {
$(window).scroll(function () {
var scrollBar = $(this).scrollTop();
var navigate = document.querySelector(".sh-body-container div").offsetTop
$(".sh-body-container div").each(function (index) {
var elTop = $(this).offset().top;
var elHeight = $(this).height();
if (scrollBar >= elTop - navigate && scrollBar < elTop + elHeight) {
$(".sh-body-sidebar ul li").eq(index).addClass("sidebarActive").siblings().removeClass("sidebarActive");
}
});
});
$(".sh-see-more").click(function(e){
e.preventDefault();
var that = $(this);
that.prev(".sh-see-more-details").toggleClass("is-active");
});
$(".hide-show").click(function(e){
e.preventDefault();
var that = $(this);
var plusSign = that.children("a").text();
if( "+" == plusSign ) {
that.children("a").text("-");
} else {
that.children("a").text("+");
}
var faq = that.next(".sh-faq-answer").toggleClass("faq-active");;
});
$(".sh-mobile-calculator-icon").click(function() {
$(".sh-calculator").addClass("show-calculator");
$(".show-filter").show();
$(".show-filter a").click(function() {
$(".sh-calculator").removeClass("show-calculator");
});
});
});
})(jQuery);

Adding active class on scroll applying at bottom not top

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();

adding additional parameters to a function

I have the function which adds a class to a div based on window position.
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if(scroll >= 300) {
$("#s-nav").addClass('s-nav-w');
} else {
$("#s-nav").removeClass('s-nav-w');
}
});
I want to add another class to add/remove. I want to add text-w to .main-nav li a class.
May be this will solve your issue
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 300) {
$("#s-nav").addClass('s-nav-w');
$(".main-nav li a").addClass('text-w');
} else{
$("#s-nav").removeClass('s-nav-w');
$(".main-nav li a").removeClass('text-w');
}
});

jQuery change active class from a to li

We use some jQuery to make our navigation sticky from some point on the page and to add an active class to sections on the page. Currently the active class is added to the a class inside the li. But I want to add this to the li instead of the a href.
How can I achieve this?
Code:
<script>
$j(window).scroll(function(){
var sticky = $j('.menu-header-product'),
scroll = $j(window).scrollTop();
var elementOffset=jQuery("#productnav").offset();
if (scroll >= elementOffset.top - 57) sticky.addClass('sticky');
else sticky.removeClass('sticky');
});
$j(window).scroll(function(){
var sticky = $j('.content'),
scroll = $j(window).scrollTop();
var elementOffset=jQuery("#productnav").offset();
if (scroll >= elementOffset.top - 57) sticky.addClass('sticky');
else sticky.removeClass('sticky');
});
$j(document).ready(function () {
$j(document).on("scroll", onScroll);
$j('a[href^="#"]').on('click', function (e) {
e.preventDefault();
$j(document).off("scroll");
$j('li').each(function () {
$j(this).parent().removeClass('active');
})
$j(this).parent().addClass('active');
var target = this.hash;
$jtarget = $j(target);
$j('html, body').stop().animate({
'scrollTop': $jtarget.offset().top - 120 /**just subtract the height of the fixed html part */
}, 500, 'swing', function () {
window.location.hash = target;
$j(document).on("scroll", onScroll);
});
});
});
function onScroll(event){
var scrollPosition = $j(document).scrollTop();
$j('nav li').each(function () {
var currentLink = $j(this);
var refElement = $j(currentLink.attr("href"));
if (refElement.position().top - 125 <= scrollPosition && refElement.position().top - 125 + refElement.height() > scrollPosition) {
$j('nav ul li a').parent().removeClass("active");
currentLink.parent().addClass("active");
}
else{
currentLink.parent().removeClass("active");
}
});
}
</script>
You can use jQuery's parent selector. So
$j(this).addClass('active');
becomes
$j(this).parent().addClass('active');
You would also need to change the selector $j('a') to $j('li'). I would recommend filtering to only lis in your navigation, i.e. $j('nav li'). Finally, you'd have to update the onScroll event similarly.

Uncaught TypeError: Cannot read property 'top' of undefined

Sorry for my bad English but i've a question with a problem.
Here is the message I've :
Uncaught TypeError: Cannot read property 'top' of undefined
Here is my function :
function onScroll(event){
var scrollPos = $(document).scrollTop();
$('#menu-center a').each(function () {
var currLink = $(this);
var refElement = $(currLink.attr("href"));
if (refElement.position().top<= scrollPos && refElement.position().top + refElement.heig
ht() > scrollPos) {
$('#menu-center ul li a').removeClass("active");
currLink.addClass("active");
}
else{
currLink.removeClass("active");
}
});
}
I don't understand because I've an other page in local with this function and it's works fine.
I've search on the web but nothing correspond to my problem.
Thanks for your help
change this line: var refElement = $(currLink.attr("href"));
in this line: var refElement = $(currLink).attr("href");
I found out the solution for the above issue. See the following code snippet
jQuery(document).ready(function($) {
$(document).on("scroll", onScroll);
});
function onScroll(event){
var scrollPos = $(document).scrollTop();
$('#menu-center a').each(function () {
var currLink = $(this);
var refElement = currLink.attr("href");
var splitEle = refElement.split('#');
if ($("#"+splitEle[1]).offset().top <= scrollPos && $("#"+splitEle[1]).offset().top + $("#"+splitEle[1]).height() > scrollPos) {
$('#menu-center ul li').removeClass("active");
currLink.parent().addClass("active");
}else{
currLink.parent().removeClass("active");
}
});
}

Categories