Infinite scroll fired twice on refresh from the bottom of page - javascript

I have an infinite scroll set up with the following piece of code.
$(window).scroll(function () {
if ($(window).scrollTop() >= $("#home_content").height() - $(window).height()) {
if (isLastPage) {
foo();
} else {
bar(); // JQuery AJAX call
}
}
});
This is inside document.ready();
The ajax call doesn't happen when the server sends a flag for the last page. This works fine in a normal scenario. But when I press F5(Refresh) from the bottom of the page, two simultaneous scroll events are fired,and it bypasses the flag (as the second call happens even before the flag is set) and duplicate data is loaded.
The only thing i know is it happens at the end of document.ready() function. Anyone, any idea??
Thanks in advance.
EDIT
There is no much relevant code other than this.
And this happens only in FF 17.
In IE 9 when I do a fast scroll down, same scroll is fired twice

You can use this debounce routine for all sort of event calls. Clean and reusable.
// action takes place here.
function infinite_scrolling(){
if ($(window).scrollTop() >= $("#home_content").height() - $(window).height()) {
if (isLastPage) {
foo();
} else {
bar(); // JQuery AJAX call
}
}
}
// debounce multiple requests
var _scheduledRequest = null;
function infinite_scroll_debouncer(callback_to_run, debounce_time) {
debounce_time = typeof debounce_time !== 'undefined' ? debounce_time : 800;
if (_scheduledRequest) {
clearTimeout(_scheduledRequest);
}
_scheduledRequest = setTimeout(callback_to_run, debounce_time);
}
// usage
$(document).ready(function() {
$(window).scroll(function() {
infinite_scroll_debouncer(infinite_scrolling, 1000);
});
});

This is just a workaround as we cannot see your complete code, but maybe thats can help:
var timeout;
$(window).scroll(function(){
clearTimeout(timeout);
timeout = setTimeout(function(){
if ($(window).scrollTop() >= $("#home_content").height() - $(window).height()){
if (isLastPage){
foo();
}else{
bar();//AJAX call
}
}
},0);
});

Related

jQuery $.get freezing on execute

I have the following script which performs an 'infinite-scroll' style function:
var next_page_link = $('.wp-pagenavi a:eq(-2)').attr('href');
$(window).scroll(function() {
if ($(window).scrollTop() > $(document).height() / 2) {
$.get(next_page_link, function(data){
if ($(data).find('.wp-pagenavi a:eq(-2)').attr('href') != next_page_link) {
next_page_link = $(data).find('.wp-pagenavi a:eq(-2)').attr('href');
var content = $(data).find('#multiple_product_top_container').html();
$('#multiple_product_top_container').append(content);
}
});
}
});
The one problem I've encountered is that each time the $.get function runs, the browser would freeze for 2-3 seconds or more and only un-freeze when the next page has been completely loaded.
My question is, is it possible to set the $.get function to run asynchronously or some other method which will eliminate the freezing?
Btw, I know that it's possible to use a server side script but I've encountered a lot of conflicts and it's more complicated involving more parsing.
Thanks
An answer to question from comment: How do I set it so that a new request can't happen until the old one finishes?
You use a semaphore:
var semaphore = true;
var next_page_link = $('.wp-pagenavi a:eq(-2)').attr('href');
$(window).scroll(function() {
if ($(window).scrollTop() > $(document).height() / 2 && semaphore) {
semaphore = false;
$.get(next_page_link, function(data){
semaphore = true;
if ($(data).find('.wp-pagenavi a:eq(-2)').attr('href') != next_page_link) {
next_page_link = $(data).find('.wp-pagenavi a:eq(-2)').attr('href');
var content = $(data).find('#multiple_product_top_container').html();
$('#multiple_product_top_container').append(content);
}
});
}
});
It would be a good idea to add a condition, that no new requests are to be made when you've already retrieved all that's possible to retrieve.

pause event while function runs

I am writing an infinite scroll function and having it run if the $(window).scrollTop() is almost as large as the documents height, and it works perfectly...
The issue is that it takes a couple seconds for the new posts to load, and in that time, if the page was scrolled, the function was called multiple times before the document got larger and therefore did not load the posts the way I intented.
Can I add a line to a function that will pause a specific event (in this case the scroll event) until the function has finished executing?
function f(){
//stop $(window).scroll
//execute code
//allow $(window).scroll
}
$(window).scroll(function(){
if(condition){
f();
}
});
John Resig did a post on this awhile ago
Here is the code he used
didScroll = false;
$(window).scroll(function() {
didScroll = true;
});
setInterval(function() {
if ( didScroll ) {
didScroll = false;
// Check your page position and then
// Load in more results
}
}, 250);
You can use $.off to unbind an event, but I would recommend to just use a variable to keep track if its been triggered or not.
This snippet will prevent f from being called until the scrolling has been set to false again.
$(window).scroll(function(){
if(this.scrolling == undefined)
this.scrolling = false;
if(this.scrolling == false){
this.scrolling = true;
f();
}
});
function f(){
//execute code
window.scrolling = false;
}
You can remove the scroll event once it's called, then reattach it if/when the load posts request is completed:
function loadPosts() {
if (condition) { // e.g. scrollTop almost equal to document height.
$(window).off('scroll', loadPosts);
$('[selector]').load('[URL-to-posts]', function(posts) {
bindScroll();
// Display posts.
});
}
}
// Binds the scroll event.
function bindScroll() {
$(window).on('scroll', loadPosts);
}
$(bindScroll); // Call on document ready.

Ajax infinite scroll feature firing twice.

For some weird reason the ajax function below is firing twice. The loadMoreResults(); function is used to retrieve data from server. I tracked the data sent to the server using google developer tool it showed that the ajax request was fired twice in a row. I guess this happens when the user scroll fast.
//Executed when user has scrolled bottom of the page
$(window).scroll(function (e) {
if ($(window).scrollTop() == $(document).height() - $(window).height()) {
loadMoreResults();
}
});
Any idea on how to prevent this from happening?
Appreciate your help.
As you said, it could be because the user is scrolling too fast and the document does not get to be updated with the new results.
Try using a flag that will prevent calling the loadMoreResults() while the function is still executing.
You set it to true when the function starts and at the end, after you get your results, you set it to false. The check of the flag can be placed right at the beginning of the loadMoreresults() function, before setting the flag to true.
eg:
function loadMoreResults() {
if (flag) return;
flag = true;
[...]
flag = false;
}
For some reason I can't figure out. Setting a flag wasn't working for me. The function call would fire twice still.
I had to use a timeout in my success callback
.then(function(resp) {
var i, len, ref, t;
ref = resp.data.users;
for (i = 0, len = ref.length; i < len; i++) {
t = ref[i];
$scope.users.push(t);
}
return setTimeout((function() {
if (resp.data.users.length > 0) {
return $scope.busy = false;
}
}), 500);

Using Javascript to detect the bottom of the window and ignoring all events when a request is loading

I have an anonymous function to detect the user has scrolled to the bottom of the window. Inside of the anonymous function, I have a call to a database that takes a while to complete.
var allowing_more = 1;
$(window).scroll(function() {
if (allowing_more == 1){
if ($(window).scrollTop() + $(window).height() == $(document).height()) {
allowing_more = 0;
//query
allowing_more = 1;
}
}
});
In this time, if the user scrolls to the bottom of the window again, it seems a queue is made holding the occurences the user scrolled to the bottom of the window while the query was loading. Upon completing of the query, these occurences are then executed.
I have a boolean statement to detect if the anonymous function is accepting more query requests but this seems to be ignored.
Is there some sort of way to ignore an anonymous function temporarily and re-enable it?
All you need is you have to stop querying your database until the previous request completes is this correct?
if this is correct
var chkFlg=0;
$(window).scroll(function() {
if ($(window).scrollTop() + $(window).height() == $(document).height()) {
if(chkFlg===1){
//query your database after you get your result from db assign 1 to chkFlg
chkFlg = 1;
}
}
});
var flag = 0;
$(window).scroll(function() {
if(flag===0){
if ($(window).scrollTop() + $(window).height() == $(document).height()) {
//query
flag = 1;
}
flag = 0;
}
});
This should work
Just follow this kind of pattern and your boolean condition should work.
safeToQuery = true; //
$(window).scroll(function() {
...
if (safeToQuery) {
safeToQuery = false;
//send query request
$.ajax({...}).done(function(data,etc){
//do whatever with the results
}).always(function (){
//regardless of whether or not the last request resulted
//in an error, make it safe to query again
safeToQuery = true;
});
}
});
Note: safeToQuery doesn't have to be a global, you could declare it as a local variable in an Immediately-Invoked Function Expression (IIFE) or just make it a property of some object that lives at least as long as you need to keep the scroll handler active.

setTimeout does bizarre things when executing in a tab that doesn't have focus [duplicate]

Is there a way to stop setTimeout("myfunction()",10000); from counting up when the page isn't active. For instance,
A user arrives at a "some page" and stays there for 2000ms
User goes to another tab, leaves "some page" open.
myfunction() doesn't fire until they've come back for another 8000ms.
(function() {
var time = 10000,
delta = 100,
tid;
tid = setInterval(function() {
if ( document.hidden ) { return; }
time -= delta;
if ( time <= 0 ) {
clearInterval(tid);
myFunction(); // time passed - do your work
}
}, delta);
})();
Live demo: https://jsbin.com/xaxodaw/quiet
Changelog:
June 9, 2019: I’ve switched to using document.hidden to detect when the page is not visible.
Great answer by Šime Vidas, it helped me with my own coding. For completeness sake I made an example for if you want to use setTimeout instead of setInterval:
(function() {
function myFunction() {
if(window.blurred) {
setTimeout(myFunction, 100);
return;
}
// What you normally want to happen
setTimeout(myFunction, 10000);
};
setTimeout(myFunction, 10000);
window.onblur = function() {window.blurred = true;};
window.onfocus = function() {window.blurred = false;};
})();
You'll see that the window blurred check has a shorter time set than normal, so you can set this depending on how soon you require the rest of the function to be run when the window regains focus.
You can do something like:
$([window, document]).blur(function() {
// Clear timeout here
}).focus(function() {
// start timeout back up here
});
Window is for IE, document is for the rest of the browser world.
I use almost the same approach as Šime Vidas in my slider
but my code is based on document.visibilityState for page visibility checking:
document.addEventListener("visibilitychange", () => {
if ( document.visibilityState === "visible" ) {
slideshow.play();
} else {
slideshow.pause();
}
});
About Page Visibility
API: https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
What you'd have to do is set up a mechanism to set timeouts at small intervals, keeping track of total elapsed time. You'd also track "mouseenter" and "mouseleave" on the whole page (the <body> or something). When the short-term timeouts expire, they can check the window state (in or out) and not restart the process when the window is not in focus. The "mouseenter" handler would start all paused timers.
edit — #Šime Vidas has posted an excellent example.
I've finally implemented a variation of #Šime Vidas' answer, because the interval was still running if I opened another program and the browser window was not visible, but the page executing the interval was the active browser tab. So, I've modified the condition to document.hidden || !document.hasFocus(). This way, if the document is hidden or the document doesn't have the focus, the interval function just returns.
(function() {
var time = 10000,
delta = 100,
tid;
tid = setInterval(function() {
if ( document.hidden || !document.hasFocus() ) { return; }
time -= delta;
if ( time <= 0 ) {
clearInterval(tid);
myFunction(); // time passed - do your work
}
}, delta);
})();

Categories