onScroll event called multiple times - javascript

I want to load more content when the user scrolls the webpage. I tried using
onScroll event javascript which is getting called multiple times
jQuery .scroll() method which is also called multiple times.
How do I handle this? Is it a browser issue?
Note: I am calling onScroll = "function()" on body tag of HTML.

On every scroll any scroll method would be called
So you should check when the user scrolls to the bottom, then load more content.

If you're getting a series of events as the window moves (similar to what happens on a resize event), then one trick is to set a timer for 1-2 seconds on the first scroll event, but not do anything yet. If a subsequent scroll event comes in before the timer fires, you stop the previous timer and set a new one. When the user stops scrolling for a brief time, the timer will fire and you can then process the scroll event. If they scroll some more, the whole process will repeat.
jQuery pseudo-code example:
var scrollTimer = null;
$("#target").scroll(function(){
if (scrollTimer) {
clearTimeout(scrollTimer); // clear previous timer
}
// set timer while we wait for a pause in scroll events
scrollTimer = setTimeout(function() {
scrollTimer = null; // timer done here
// do your dynamic loading here
}, 1000);
});

Load content while scrolling: http://www.webresourcesdepot.com/load-content-while-scrolling-with-jquery/

Related

Is it good idea to use jquery function that run each 500ms?

I created some kind of lazy load for images. It works like this:
Every 500ms it check photoes which one you see on device and if you see it begin to load real image and this function will never run for images that loaded but if image cant load it will try again when you see this image again.
Is there any problem to use that kind of function every 500ms?
It sounds like you're using this in response to the images coming into view? Rather than polling every 500ms all the images on the page to see if they're in view, perhaps it would be better to trigger the check only when the page has scrolled (or whatever causes images to scroll. You could still limit this to be no more frequent than once every 500ms, but it has the benefit of:
Not having a 500ms interval loop running all the time
Not checking the images in view unnecessarily
I'll assume the images come in and out of view as the user scrolls, so what you'd want to do in that instance is as follows:
Bind an event to $(window).scroll
Have it fire an event after a fixed period with setTimeout (500ms in your case).
Cancel that timer if the user scrolls again and start it (to prevent it firing multiple times.
Listen for the event firing and perform your image check there.
Here's an example of how the code might look:
var scrollIntervalTimeout;
$(window).on('scroll', function() {
// Cancel the timeout and start it again
clearTimeout(scrollIntervalTimeout);
scrollIntervalTimeout = setTimeout(function() {
$(window).trigger('scrollDidEnd');
}, 500); // 500ms delay before firing the event
});
// Listen for the scrollDidEnd event
$(window).on('scrollDidEnd', function() {
// Perform your image check here
});

How to prevent spamming of an onclick listener?

This is a new issue for me and I've been unable to find any information about this.
I have a simple onclick listener that performs a smooth scroll to a target on the page. Here is the code below:
$(".nav-scroll").click(function (event) {
var ID = this.hash;
//has a few extra conditionals here specific to the page
$('html,body').animate({ scrollTop: $(ID).offset().top }, 1000);
});
Ultimately, the scenario is that this function takes time to execute. Not much time, but it does add up if someone spams the link on the page and the browser starts queuing the function calls. Now spamming is an extreme case, but even after 3 or 4 consecutive clicks it hinders the user experience while they can't scroll down the page because the page is trying to scroll them back to the target 3 or 4 times.
All my research has been able to turn up is checking if a window has an event listener already like found here: JavaScript - how to check if event already added or listing all the event listeners on an element like here: jQuery find events handlers registered with an object , but nothing to check to see if something is currently running.
Is it possible to prevent this side effect by dumping all previous listener calls on the page mid execution before executing or by another method? Or is this something that is not offered by JavaScript? If so, is there strategies to get around this like checking to see if the function is already executing?
From the conversation in the comments, it sounds like you want the users to be able to click on the element as fast as they want to, and have it interrupt the existing animation and start a new one, rather than queueing them up and causing it to scroll around the page. You can achieve this by simply using stop:
$(".nav-scroll").click(function (event) {
var ID = this.hash;
//has a few extra conditionals here specific to the page
//call stop to kill old animations
$('html,body').stop().animate({ scrollTop: $(ID).offset().top }, 1000);
});
A debouncing approach would prevent them from clicking at all until the animation ends, rather than allowing them to click one element, realise they've clicked in slightly the wrong place and quickly click the right element.
You need this:
var debounce = false;
$(".nav-scroll").click(function (event) {
if (debounce) return;
debounce = true;
var ID = this.hash;
//has a few extra conditionals here specific to the page
$('html,body').animate({ scrollTop: $(ID).offset().top}, 1000, function() {debounce=false;});
});
Basically, it disables the onclick event on fire until it is scrolled up, then enables the event.
You could wrap you onClick function in a throttle which keeps it from executing again while it's scrolling.
Like so:
// lodash is defined here as _
var animationTime = 1000;
var scrollTo = _.throttle(function (event) {
var ID = this.hash;
//has a few extra conditionals here specific to the page
$('html,body').animate({ scrollTop: $(ID).offset().top }, animationTime);
}, animationTime);
$(".nav-scroll").click(scrollTo);
Is this case the first time the users clicks the function gets called but if they click again within the time frame (the 1000ms) the the function does not execute again. Only after the time has passed can the user invoke the function again.
Here you can find the documentation for lodash throttle:
https://lodash.com/docs#throttle

On Scroll fires automatically on page refresh

Im halfway down my page as I have an anchor. I also have a window scroll event:
$(window).scroll(function(){
});
When I refresh the page, the scroll event fires. Is there a way to prevent this on the refresh but still listen for the scroll event when the user scrolls?
I believe your scroll code only fires if you refresh the page and the page is scrolled. That's because the browser will reload the page, and then scroll to the original position.
The solution suggested by Arnelle does not work well, because the scroll event only fires initially if the page was scrolled when you refreshed it.
Hack Alert
What I found that does work is waiting to set the scroll handler. Be careful, I'm using magic numbers that may not work on all connections.
//Scroll the page and then reload just the iframe (right click, reload frame)
//Timeout of 1 was not reliable, 10 seemed to be where I tested it, but again, this is not very elegant.
//This will not fire initially
setTimeout(function(){
$(window).scroll(function(){
console.log('delayed scroll handler');
});
}, 10);
//This will fire initially when reloading the page and re-establishing the scroll position
$(window).scroll(function(){
console.log('regular scroll handler');
});
div {
height: 2000px;
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
</div>
And yes, I know I bashed Arnelle by saying they patched a problem without understanding, and here I am, suggesting a patch. The only difference is that I think I understand the problem.
My main question to the OP is. Most scroll handlers that I've written work fine if called multiple times, what is the problem with your handler being called an extra time?
You can use a flag variable to detect whether the scroll event is the initial scroll event or not, effectively stopping the callback function's execution for the scroll event on page reload.
var initialScrollEvent = true;
$(window).scroll(function() {
if (!initialScrollEvent) {
// callback function body
}
initialScrollEvent = false;
});

Disabling Mouse Wheel for X Milliseconds with javascript?

I have a Website with RoyalSlider and Mousewheel support. http://www.linus.de/mark/drei.php
Everything works fine, but when i use my macbook (touchpad) the thing is that i fire several mousewheel events at a time when scrolling. so basically i want the script to pause for the time (or a bit less) it takes for one slide to change...
What i would need is a javascript which freezes the mousewheel for x milliseconds each time it's been triggered (after sending 1 or -1 to the slider)...
A Timer with a call back and a flag could work. When you start to scroll you set the flag and not allow the scroll wheel to function, see This Answer on how to disable the scroll wheel. When the timer fires (1 second or so) you reset the flag to let the person scroll again. See This page for how to set up a timer with a call back
I can't give you a full code example since you didn't give any code to us but here's the solution.
When you scroll the mouse, a scroll animation begins. Create a variable somewhere outside the event handler, let's say
var animationInProgress = false;
and set it to true right before the animation begining. Then, this RoyalSlider plugin must have some kind of complete handler (I bet it has - it's paid though) - a parameter where you can put a function to be called when the animation is over. So, you put there a function similar to that:
function() {
animationInProgress = false;
}
The last thing is to check the value of the animationInProgress variable each time you want to run an animation
if (false === animationInProgress) {
//run the animation
}
I hope you get the idea.

How do I detect whether scroll events are fired *only once* like on touch devices?

iOS devices (and likely Android ones) have a different scrolling behavior: The scroll event is only fired once after the entire scroll is done.
How do I detect whether the browser behaves this way?
I could use window.Touch or Modernizr.touch but they don't tell me anything about the scroll behavior, it would be like asking if someone is French to understand whether they like croissants, right? :)
I think you're right about the detection because there will be some devices that will support both touch and mouse behaviors (like Windows 8 tablets), some will only support touch (phones) and some will only support mouse (desktops). Because of that, I don't think you can conclusively say that a device only has one behavior as some could have both.
Assuming that what you're really trying to do is to figure out whether you should respond immediately to every scroll event or whether you should use a short delay to see where the scroll destination ends up, then you could code a hybrid effect that could work well in either case.
var lastScroll = new Date();
var scrollTimer;
window.onscroll = function(e) {
function doScroll(e) {
// your scroll logic here
}
// clear any pending timer
if (scrollTimer) {
clearTimeout(scrollTimer);
scrollTimer = null;
}
var now = new Date();
// see if we are getting repeated scroll events
if (now - lastScroll < 500){
scrollTimer = setTimeout(function() {
scrollTimer = null;
doScroll(e);
}, 1000);
} else {
// last scroll event was awhile ago, so process the first one we get
doScroll(e);
}
lastScroll = now;
};
doScroll() would be your scroll processing logic.
This gets you a hybrid approach. It always fires on the first scroll event that arrives when there hasn't recently been a scroll event. If there are a series of scroll events, then it fires on the first one and then waits until they stop for a second.
There are two numbers that you may want to tweak. The first determines how close scroll events must be to consider them rapid fire from the same user action (current set to 500ms). The second determines how long you wait until you process the current scroll position and assume that the user stopped moving the scrollbar (currently set to 1s).

Categories