if($(window).scrollTop() + $(window).height() > $(document).height() - 300){
//query data & append
}
I have a page detect scroll bar - query data & append.
My problem is when I check 'network' from browser
it send query 3 or 4 times per scroll.(because mouse wheel scroll down very fast)
Is any way to solve this so I don't need to query unnecessary data
//set a variable for apply event
var start=1; // now below event work
if(($(window).scrollTop() + $(window).height() > $(document).height() - 300) && start){
start=0;// now it set 0 it s not work until your work done
//query data & append
start=1 //now your work done and it comes it this action again
}
Try to check if an ajax call(query) was made already, like this:
if($(window).scrollTop() + $(window).height() > $(document).height() - 300){
if(!ajaxCall)
{
ajaxCall = true;
//query data & append
if (success)
ajaxCall = false;
}
}
Don't forget to declare your ajaxCall somewhere in your code so it will not end in the global scope.
What this does is:
initialize a variable to check if a request has been made already
if no request was made, set the variable to true and make a request
when the request comes back with a success, set it to false
A smarter way to achieve this is to detect the end of scroll event on each scroll and write the code in it:
var delay = 1000;
var timeout = null;
$(window).bind('scroll',function(){
clearTimeout(timeout);
timeout = setTimeout(function(){
alert('scrolling stopped');
if($(window).scrollTop() + $(window).height() > $(document).height() - 300){
//query data & append
}},delay);
});
Related
I am trying to load more items on-scroll. The code works and the user reaches the bottom of the page. Every time the user scrolls to the bottom of the page, 9 items are loaded.
The issue appears when I try to load 9 items before the user reaches the bottom of the page. Then wait for those items to be loaded and then check again the condition (currentScroll >= goal).
At this point as soon as the condition is TRUE (currentScroll >= goal) all items are loaded at once.
I am guessing that this is happening because the currentScroll variable keeps counting while scrolling and the first group of items has not been yet loaded. As a result the $(document).height() is still the same, which affect the goal variable: var goal = $(document).height() - $(window).height();
I tried to use a while loop (see the commented section at my code) but the code crashes.
Is there any way to make the program wait for the group of items (9 items) to be loaded when the condition is TRUE and then check again?
$(window).scroll(function() {
var currentScroll = $(window).scrollTop();
var goal = $(document).height() - $(window).height(); // Bottom of the page
goal = goal*0.5; // Load more items before reach bottom of the page
// The following parts check if all the items are loaded. That works!!
var result_count = document.getElementsByClassName('yacht-count')[0].innerHTML
total_results_to_show = group_of_villas_showed*results_to_show;
if(result_count/total_results_to_show<=1){
goal = currentScroll*2;
console.log("Finish");
}
// Check if the current scroll is greater than the setted goal
if (currentScroll >= goal){
console.log("start loading villas");
ajaxGet(guests_value,destinations_value,sort_by,current_page);
current_page++;
group_of_villas_showed+=1;
console.log("loading villas");
}
// With the use of this Loop program crashes
/*
while(currentScroll >= goal){
goal = $(document).height() - $(window).height();
var currentScroll = $(window).scrollTop();
goal = goal*0.5;
}
*/
});
ajaxGet = (guests_value,destinations_value,sort_by,page, replace = false) => {
$.ajax({
type: 'GET',
url: ajax_url,
data: {
guests: guests_value,
destination: destinations_value,
sort_by: sort_by,
page:page,
},
dataType: 'json',
beforeSend: function(){
$('#loading-image').removeClass('hide');
$('.yachts-search-page').addClass('loading-more');
},
success: function (data) {
//console.log('ajax success');
$('.yachts-search-page').removeClass('loading-more');
$('#loading-image').addClass('hide');
if(replace){
$('body .load-more-wrapper').show();
$('body .yachts-inner').html(data.content);
current_page = 1;
}
else
$('body .yachts-inner').append(data.content);
$('body .yacht-count').text(data.yacht_count);
newQueryString(guests_value,destinations_value,sort_by,page);
},
error: function(data){
//console.log('error wtf');
}
});
}
I found a solution thanks to Jay Kariesch's comment on this site. I used _.throttle which checks if the condition is TRUE every 300ms which is enough for the next group of villas to be loaded.
Thank you so much for your replies guys. You were extremely helpful!!
This is my working code now:
$(document).ready(function(){
// Check every 300ms the scroll position
$(document).on('scroll', _.throttle(function(){
check_if_needs_more_content();
}, 300));
function check_if_needs_more_content() {
pixelsFromWindowBottomToBottom = 0 + $(document).height() - $(window).scrollTop() -$(window).height();
// Check if all the items are loaded.
var result_count = document.getElementsByClassName('yacht-count')[0].innerHTML
total_results_to_show = group_of_villas_showed*results_to_show;
//console.log("results_to_show",results_to_show);
console.log("total_results_to_show",total_results_to_show);
console.log("result_count",result_count);
if(result_count/total_results_to_show<=1){
finish_check=1;
console.log("Finish");
}
else
finish_check=0;
//Items load condition
if ((pixelsFromWindowBottomToBottom < 500)&&(finish_check==0)){
//console.log("start loading villas");
ajaxGet(guests_value,destinations_value,sort_by,current_page);
current_page++;
group_of_villas_showed+=1;
}
}
});
I have a simple website consisting of a single page. Usage behavior is being tracked via Piwik. Due to the design of the page, users usually resort to scrolling through it instead of using the navbar and clicking on links, making link trackinga very uninformative method to get some insight into how the website is being used. To track user behavior, I have a js function using "scroll" that determines the location of the user on the page and then sends a request to the tracking server:
setInterval(reportposition, 1000);
function reportposition () {
$(function () {
var $win = $(window);
$win.scroll(function () {
if ($win.scrollTop() == 0) {
_paq.push(['trackEvent', 'Scroll', 'PageTop']);
} else if (($(document).height() - $win.scrollTop()
< 7540) && ($(document).height() - $win.scrollTop() > 7500 )) {
_paq.push(['trackEvent', 'Scroll', 'About']);
}
else if ($win.height() + $win.scrollTop()
== $(document).height()) {
_paq.push(['trackEvent', 'Scroll', 'PageBottom']);
}
});
});
};
However, every scroll that satisfies one of the conditions does so dozens of times and thus sends dozens of tracking requests to the server. I tried to lower the frequency the function is run with setInterval, but the effect is negligible. Is there any way to get the function to fire off only once when a condition has been met until a different condition is satisfied?
Using scroll to check for the position of the user seems to be rather demanding regarding CPU cycles as sometimes hundreds of events can occur with a simple scroll. Is there any way to solve this problem with as little CPU usage as possible?
The solution here is to check if the scrollTop is equal to the scrollTop of the current div the user has scrolled on.
In terms of CPU, look at https://techoctave.com/c7/posts/60-simple-long-polling-example-with-javascript-and-jquery . This is one solution; more ideally you should look at using Websockets (i.e., using socket.io with node.js).
scroll event is unnecessary in your case, since it is only useful for detecting if the user has scrolled whereas you can check that by only comparing with scrollTop() value of a second ago. You also dont need to access height values if they do not
setInterval(reportposition, 1000);
var $win = $(window);
function reportposition () {
$(function () {
if(scrollTop == $win.scrollTop()){
//same position
}
scrollTop = $win.scrollTop();
winHeight = $win.height();
docHeight = $(document).height();
if (scrollTop == 0) {
_paq.push(['trackEvent', 'Scroll', 'PageTop']);
}else if ((docHeight - scrollTop < 7540)
&& (docHeight - scrollTop > 7500 )) {
_paq.push(['trackEvent', 'Scroll', 'About']);
}else if (winHeight + scrollTop
== docHeight) {
_paq.push(['trackEvent', 'Scroll', 'PageBottom']);
}
});
};
Other way around, inside the scroll event, you can check how much time has passed and decide whether to process or not.
I am appending some php files using ajax every time the user scrolls to the bottom of the window.
$(window).scroll(function(){
if($(window).scrollTop() + $(window).height() > $(document).height() - 100){
$(window).unbind('scroll');
// Function to append php files using ajax
}
})
I want to recognize the next time user scrolls to bottom of the page and append some other php files, but how do I find out the next(1 or many) events that scroll to bottom of the page?
Example: First scroll to bottom: Append 1.php 2.php
second scroll to bottom: append 3.php 4.php
third scroll to bottom: append 5.php 6.php
4th scroll to bottom: show footer
I dont need infinite scroll plugin. Because there is no concept of footer there.
You need to maintain a counter variable which counts how many requests you've made. You can then pass that to the server which will then return the required information. Something like this:
var requestCount = 0;
$(window).scroll(function(){
if ($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
$(window).unbind('scroll');
// Function to append php files using ajax
requestCount++;
if (requestCount < 4) {
$.ajax({
url: 'foo.php',
data: { page: requestCount },
success: function() {
// append your items
}
}
}
else {
// show footer
}
}
})
In your PHP you would need to take the page variable and return the relevant items.
var count = 1;
$(window).scroll(function(){
if($(window).scrollTop() + $(window).height() > $(document).height() - 100){
$(window).unbind('scroll');
if(count<4)
// Function to append php files using ajax
call_your_ajax_with_url(count+'.php');
call_your_ajax_with_url(count+1 +'.php');
count+=1;
else showFooter();
}
});
would do the work.
I am creating a blog on django/webfaction. My hompage currently displays 4 posts by default (posts are limited to 4 on queryset in urls.py). Now I would like to load four more posts once user reaches the bottom of the page and keep on continuing that until last post is reached. How to achieve this?
If you want to load your content on reaching extreme bottom of document use following code:
$(window).scroll(function()
{
if($(window).scrollTop() == $(document).height() - $(window).height())
{
// load your content
}
});
If you want to load content before reaching 100 pixel of bottom use
var loading= false;
$(window).scroll(function() {
if (!loading && ($(window).scrollTop() > $(document).height() - $(window).height() - 100)) {
loading= true;
// your content loading call goes here.
loading = false; // reset value of loading once content loaded
}
});
You can try something like this..
var processScroll = true;
$(window).scroll(function() {
if (processScroll && $(window).scrollTop() > $(document).height() - $(window).height() - 100) {
processScroll = false;
// your functionality here
processScroll = true;
}
});
You can make Ajax call to fetch more posts on 'onscroll' event of element (possibly on body in your case).
You can make the same call using jquery's '.scroll()' documented here: http://api.jquery.com/scroll/
You can probably maintain a previous-top statement to determine direction of current scroll.
I am trying to set up infinite-scroll on a site I am developing with Coldfusion, I am new to javascript and jquery so I am having some issues wrapping my head around all of this. Do I need to have pagination on my site in order to use the infinite-scroll plugin, or is there a way to do it with out it?
You do not need infinite scroll plug-in for this. To detect when scroll reaches end of page, with jQuery you can do
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 10) {
//Add something at the end of the page
}
});
Demo on JsFiddle
I'm using Hussein's answer with AJAX requests. I modified the code to trigger at 300px instead of 10px, but it started causing my appends to multiply before the AJAX request was finished since the scroll call triggers much more frequently in a 300px range than a 10px range.
To fix this, I added a trigger that would be flipped on successful AJAX load. My code looks more like this:
var scrollLoad = true;
$(window).scroll(function () {
if (scrollLoad && $(window).scrollTop() >= $(document).height() - $(window).height() - 300) {
scrollLoad = false;
//Add something at the end of the page
}
});
then in my AJAX response, I set scrollLoad to true.
I built on top of Hussein's little example here to make a jQuery widget. It supports localStorage to temporarily save appended results and it has pause functionality to stop the appending every so often, requiring a click to continue.
Give it a try:
http://www.hawkee.com/snippet/9445/
$(function(){
$(window).scroll(function(){
if($(document).height()<=$(window).scrollTop()+$(window).height()+100){
alert('end of page');
}
});
});
Some one asked for explanation so here is the explanation
here $(document).height()-->is the height of the entire document.In most cases, this is equal to the element of the current document.
$(window).height()-->is the height of the window (browser) means height of whatever you are seeing on browser.
$(window).scrollTop()-->The Element.scrollTop property gets or sets the number of pixels that the content of an element is scrolled upward. An element's scrollTop is a measurement of the distance of an element's top to its topmost visible content. When an element content does not generate a vertical scrollbar, then its scrollTop value defaults to 0.
$(document).height()<=$(window).scrollTop()+$(window).height()+100
add $(window).scrollTop() with $(window).height() now check whether the result is equal to your documnet height or not. if it is equal means you reached at the end.we are adding 100 too because i want to check before the 100 pixels from the bottom of document(note <= in condition)
please correct me if i am wrong
I had same problem but didn't find suitable plugin for my need. so I wrote following code. this code appends template to element by getting data with ajax and pagination.
for detecting when user scrolls to bottom of div I used this condition:
var t = $("#infiniteContent").offset().top;
var h = $("#infiniteContent").height();
var ws = $(window).scrollTop();
var dh = $(document).height();
var wh = $(window).height();
if (dh - (wh + ws) < dh - (h + t)) {
//now you are at bottom of #infiniteContent element
}
$(document).ready(function(){
$.getJSON("https://jsonplaceholder.typicode.com/comments", { _page: 1, _limit:3 }, function (jsonre) {
appendTemplate(jsonre,1);
});
});
function appendTemplate(jsonre, pageNumber){
//instead of this code you can use a templating plugin like "Mustache"
for(var i =0; i<jsonre.length; i++){
$("#infiniteContent").append("<div class='item'><h2>"+jsonre[i].name+"</h2><p>"+jsonre[i].body+"</p></div>");
}
if (jsonre.length) {
$("#infiniteContent").attr("data-page", parseInt(pageNumber)+1);
$(window).on("scroll", initScroll);
//scroll event will not trigger if window size is greater than or equal to document size
var dh = $(document).height() , wh = $(window).height();
if(wh>=dh){
initScroll();
}
}
else {
$("#infiniteContent").attr("data-page", "");
}
}
function initScroll() {
var t = $("#infiniteContent").offset().top;
var h = $("#infiniteContent").height();
var ws = $(window).scrollTop();
var dh = $(document).height();
var wh = $(window).height();
if (dh - (wh + ws) < dh - (h + t)) {
$(window).off('scroll');
var p = $("#infiniteContent").attr("data-page");
if (p) {
$.getJSON("https://jsonplaceholder.typicode.com/comments", { _page: p, _limit:3 }, function (jsonre) {
appendTemplate(jsonre, p);
});
}
}
}
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<div id="infiniteContent"></div>
If you have a scrollable element, like a div with scroll overflow, but no scrollable document/page, you can take this way.
$(function () {
var s = $(".your-scrollable-element");
var list = $("#your-table-list");
/* On element scroll */
s.scroll(function () {
/* The scroll top plus element height equals to table height */
if ((s.scrollTop() + s.height()) == list.height()) {
/* you code */
}
});
});
I wrote this function using Hussein and Nick's ideas, but I wanted it to use promises for the callback. I also wanted the infinite scrolling area to be on a fixed div and not just the window if the div is sent into the options object. There is an example of that in my second link below. I suggest using a promise library like Q if you want to support older browsers. The cb method may or may not be a promise and it will work regardless.
It is used like so:
html
<div id="feed"></div>
js
var infScroll = infiniteScroll({
cb: function () {
return doSomethingPossiblyAnAJAXPromise();
}
});
If you want the feed to temporarily stop you can return false in the cb method. Useful if you have hit the end of the feed. It can be be started again by calling the infiniteScroll's returned object method 'setShouldLoad' and passing in true and example to go along with the above code.
infScroll.setShouldLoad(true);
The function for infinite scrolling is this
function infiniteScroll (options) {
// these options can be overwritten by the sent in options
var defaultOptions = {
binder: $(window), // parent scrollable element
loadSpot: 300, //
feedContainer: $("#feed"), // container
cb: function () { },
}
options = $.extend(defaultOptions, options);
options.shouldLoad = true;
var returnedOptions = {
setShouldLoad: function (bool) { options.shouldLoad = bool; if(bool) { scrollHandler(); } },
};
function scrollHandler () {
var scrollTop = options.binder.scrollTop();
var height = options.binder[0].innerHeight || options.binder.height();
if (options.shouldLoad && scrollTop >= (options.binder[0].scrollHeight || $(document).height()) - height - options.loadSpot) {
options.shouldLoad = false;
if(typeof options.cb === "function") {
new Promise(function (resolve) {resolve();}).then(function() { return options.cb(); }).then(function (isNotFinished) {
if(typeof isNotFinished === "boolean") {
options.shouldLoad = isNotFinished;
}
});
}
}
}
options.binder.scroll(scrollHandler);
scrollHandler();
return returnedOptions;
}
1 feed example with window as scroller
2 feed example with feed as scroller