Do something once in $(window).scroll function during multiple conditional statements - javascript

This is throwing me for a loop..
The basic idea is we're using $(window).scroll() and as you scroll down the page, when an element is in view by using offset() with scrollTop "do something" then when you hit the next element down the page "do something more".
However, because the scroll event (probably the wrong term) fires every single time in the conditional statement because technically the statement is true every scroll, I need it to only fire once, but then be able to 're-fire again' one time when the next conditional happens.
$(window).scroll(function(){
let windowTop = $(window).scrollTop()
if( windowTop > $('.element').offset().top && windowTop < $('.element2').offset().top ) {
doSomething(); // want this to only fire once
} else if( windowTop > $('.element2').offset().top ) {
doSomething(); // want this to only fire once
}
});
I had a theory about possibly setting a variable to true so it only fire's doSomething() once, but then when it's inside the 2nd conditional statement I can't wrap my head around undoing / resetting it.
let fired = false;
$(window).scroll(function(){
let windowTop = $(window).scrollTop()
if( windowTop > $('.element').offset().top && windowTop < $('.element2').offset().top ) {
if(!fired){
doSomething();
fired = true;
}
} else if( windowTop > $('.element2').offset().top ) {
// need to somehow set fired to false again so it triggers once then sets back to true
if(!fired){
doSomething();
fired = true;
}
}
});
Hope I somehow made sense!

Consider the following.
var fire = {
"element1": true,
"element2": true
};
$(window).scroll(function(event){
var windowTop = $(window).scrollTop();
console.log("Window Scroll Top: " + windowTop);
if( fire.element1 && (windowTop > $('.element').offset().top && windowTop < $('.element2').offset().top) ) {
console.log("Do Something!", $('.element').offset().top);
fire.element1 = false;
doSomething();
} else if( fire.element2 && (windowTop > $('.element2').offset().top) ) {
console.log("Do Something!", $('.element2').offset().top);
fire.element2 = false;
doSomething();
}
});
The logic here is we check if we should fire the event for each element. In this way we have a more complex IF condition. Fire for that element must be true and the Scroll position must have gone down far enough.
If the Top of the element is 100, this condition should only be true at one time and one time only, when windowTop is a value of 101 or higher. Now if you want it to trigger when the element is fully in view, you need the Top plus the Height. If it's 40px tall, then it would be 140 (Top + Height).

Related

Nav Shrink on Scroll or Resize

I'm trying to apply a series of classes to a nav that cause it to shrink if the window is either resized or scrolled passed a certain point. However, I believe my conditions are cancelling each other out, and I'm not sure how to structure the if-statements or if it is better to just pass a variable.
Here's what I am trying to accomplish:
If the window is resized between a certain set of media queries, shrink the nav
If the window is outside of those break-points, and the user scrolls passed 1 (I used one just for example purposes in my code so I could see it right away) the nav will shrink and if they scroll up again, it will become it's full size
My code is here:
$(document).ready(function() {
var logo = $('.logo');
var topLevelListItems = $('.mainNav li');
var navShrink = false;
var mQ = window.matchMedia( '(min-width: 100px) and (max-width: 770px)' );
$(window).resize(function() {
if ( mQ.matches ) {
$('nav').addClass('shrink');
$('.nav-fixedWidth').addClass('shrink');
logo.addClass('shrink');
topLevelListItems.addClass('shrink');
navShrink = true;
}
else{
$('nav').removeClass('shrink');
$('.nav-fixedWidth').removeClass('shrink');
logo.removeClass('shrink');
topLevelListItems.removeClass('shrink');
navShrink = false;
}
});//end of resize function
$(window).onscroll(function(){
if( !(mQ.match) && $(this).scrollTop >= 1 ) {
$('nav').addClass('shrink');
$('.nav-fixedWidth').addClass('shrink');
logo.addClass('shrink');
topLevelListItems.addClass('shrink');
navShrink = true;
} else {
$('nav').removeClass('shrink');
$('.nav-fixedWidth').removeClass('shrink');
logo.removeClass('shrink');
topLevelListItems.removeClass('shrink');
navShrink = false;
}
});//end of scroll function
});//end of doc
Could it simply be a typo in your onscroll function?
i.e you have:
if( !(mQ.match) && $(this).scrollTop >= 1 ) { ...
should it not be:
if( !(mQ.matches) && $(this).scrollTop >= 1 ) { ...

Fire jquery upon reaching bottom of page (only once)

I have the below script, which is initialising a function upon reaching the bottom of the page (with a 1px threshold, as it doesn't seem to work without this). It is workming fine, but I'd like it to only work when reaching the bottom of the page the first time, if a user scrolls back up and down, nothing should happen.
Any suggestions?
JS
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() > ($(document).height() - 1) ) {
// Function goes here
}
});
Use some flag for that:
var hasScrolled = false;
$(window).scroll(function() {
if(!hasScrolled && $(window).scrollTop() + $(window).height() > ($(document).height() - 1) ) {
hasScrolled = true
// Function goes here
}
});
add another variable that would keep track if the user has scrolled already.
`
scrolled = false;
if($(window).scrollTop() + $(window).height() > ($(document).height() - 1) && !scrolled) {
// Function goes here
scrolled = true;
}

Jquery window scroll. call just one time

Hi I have one question about jquery window scroll function. I have code somthing like this.
$(window).scroll(function(){
if($(window).scrollTop() > $(".pages").offset().top) {
$('.top-slider').slick('slickPause');
}else {
$('.top-slider').slick('slickPlay');
}
});
Ok every time when you scroll if first is true it call every 1px scrolled window. Is that way to call just one time if true but check on scroll if other is true call that just one time?
Thanks for your answers :)
Try with a flag, something like this:
var paused = false;
$(window).scroll(function(){
if( $(window).scrollTop() > $(".pages").offset().top ) {
if( !paused ){
$('.top-slider').slick('slickPause');
paused = true;
}
}else {
if( paused ){
$('.top-slider').slick('slickPlay');
paused = false;
}
}
});
Adding a test variable will be a solution here :
var checkDown = true;
var checkUp = false;
$(window).scroll(function(){
if($(window).scrollTop() > $(".pages").offset().top && checkDown ) {
$('.top-slider').slick('slickPause');
checkDown = false;
checkUp = true;
}else if(checkUp) {
$('.top-slider').slick('slickPlay');
checkDown = true;
checkUp = false;
}
});
I tell you another solution, is a debouncer. Debounce functions make scroll and resize events more efficient, because stop the event firing till the end of the first fired event.
You can view a debounce function with underscore.js library.
http://underscorejs.org/#debounce
The use is simple:
var debounced = _.debounce(myFunction, 1000);
$(window).scroll(debounced);

Eliminate Recursion on Events Triggered Inside Mousewheel Event

I'm working on a project that's using a sort of dummy pagination. The body is set to overflow: hidden and currently the only way to navigate the pages is by physically clicking on either links in the nav pane, or on sroll-down/scroll-up buttons. Here's an idea of the events that are triggered when those elements are physically clicked:
var links = $('#topnav, .top-mid a'), l = links.length - 1;
var id = 0;
$('.scrollDown, .scrollUp, .top-mid a, body.home #topnav').click(function (e) {
e.preventDefault();
var $this = $(this);
if ($this.is('.scrollDown') && id < l) id++;
if ($this.is('.scrollUp') && id > 0) id--;
if ($this.is('#topnav, .top-mid a')) id = links.index(this);
// Body is animated down or up and elements are
// shown or hidden depending on what was clicked and
// and what the var id is currently equal to
});
The idea is to trigger exactly ONE click of the scroll button on a mousewheel event. So something close to as simple as this, but that actually works:
$(window).on('mousewheel', function(e){ // I realize this will not work in FF
var evt = e.originalEvent.wheelDelta;
console.log(evt);
// Scrolling Down
if (evt < 0) {
$('.scrollDown').click(); // This fires recursively as long as wheelDelta !== 0
}
});
How can I either force wheelDelta to only increment or decrement by one, or, barring that, how can I eliminate the recursion on the click event?
I've been at this for a while, and read lots of posts and haven't been able to crack it. I've also tried fullPage.js, but it's rather heavy and doesn't really suit my project for other various reasons.
I finally solved this, and of course it turned out to be quite simple. It was a matter of toggling a boolean value inside the click() event, but only after all the animations had taken place. Like this:
var scrolled = false;
$(window).on('mousewheel', function(e){
var evt = e.originalEvent.wheelDelta;
// Scrolling Down - Only fire the click event if it hasn't already fired
if (evt < 0 && !scrolled) {
$('.scrollDown').click();
// Scrolling Up
} else if (evt > 0 && !scrolled) {
$('.scrollUp').click();
}
});
// Toggle the scrolled variable inside the original click event
$('.scrollDown, .scrollUp').click(function (e) {
e.preventDefault();
var $this = $(this);
if ($this.is('.scrollDown') && id < l) {
id++;
scrolled = true;
setTimeout(function(){
scrolled = false;
}, 1500);
}
if ($this.is('.scrollUp') && id > 0) {
id--;
scrolled = true;
setTimeout(function(){
scrolled = false;
}, 1500);
}
// Other events here
// The timeout has to be set high enough to assure
// that the mousewheel event is finished
});

How to prevent duplicate events when scroll in jQuery?

I have 4 divs like;
<div class="diva">diva</div>
<div class="divb">divb</div>
<div class="divc">divc</div>
<div class="divd">divd</div>
They are 400px wide and high. I want to alert a when div b scrolls to top of page, and did using scroll function and scrollTop method. Each time when scroll, it check if scrollTop() if lager than 400, and alert a. But if I don't click the on the ok button of alert window, if I continue scrolling, multiple alerts will come, and I have to close them all.
But I just want one alert, and even if I continue scrolling, I want no more alerts. Also if the scrollTop is below 400px, I want to alert b (here also, I don't want repeats). If I got alert a, and if I scroll in opposite direction, and if scrollTop becomes below 400px, I want alert b, no problem for that.
Here is the fiddle.
please add this script on your file JS and try this script:
$(document).ready(function() {
$(window).scroll(function(){
var xx = $(document).scrollTop();
if(xx > jQuery(".divb").height()){
alert("a");
}else{
alert("b");
}
});
});
You are popping alerts on a 'scroll' event which happens every time you scroll..
if this is just a debugging annoyance, what you can do is use console.log('a') instead - example
If you wanted the actual function to run once for each time you reach it you can do this:
var a = false;
$(window).scroll(function(){
var xx = $(document).scrollTop();
if(xx > 400){
if (!a) {
alert("a");
a = true;
}
}else{
if (a) {
alert("b");
a = false;
}
}
});
fiddle for this example
The easiest way to avoid any confusion would be to keep state of scroll actions.
Demo: http://jsfiddle.net/abhitalks/uwUvC/1/
var last = 0, // last scroll-top to determine scroll direction
scrolledUp = false, // to cache state of scroll up
scrolledDown = false; // to cache state of scroll down
$(window).scroll(function (event) {
var current = $(this).scrollTop();
if (current > last) { // if scrolled down
if (current > 400 && !scrolledDown) { // check position and state
alert("A");
scrolledDown = true; // reset scroll down state
}
} else { // if scrolled up
if (current < 400 && scrolledDown && !scrolledUp) {
alert("B");
scrolledUp = true; // reset scroll up state
}
}
last = current; // keep current position to check direction
});
This way you are sure about when you are scrolling up and when you are scrolling down. Keep state of scroll in respective variables and check them.
The alerts fire only once in each direction.

Categories