72

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?

John Slegers
  • 38,420
  • 17
  • 182
  • 152
rajh2504
  • 1,256
  • 2
  • 18
  • 37
  • @francis what do you mean by costly. You don't have to bind everything to the scroll. It depends of what want to do. This is a generic example. scroll is cross browser supported. – Hussein Feb 27 '12 at 02:34
  • 1
    Try this awesome infinite scroll - https://github.com/yairEO/infinite – vsync Sep 13 '15 at 21:05
  • @vsync not blaming you but it seems a little buggy when you scroll, for me when I scroll it jumps from 20 to 40? Moz Firefox fyi – Shaun Moore Sep 16 '20 at 11:29
  • @ShaunMoore - depends on the OS and if you have some smooth-scroll enabled. I've designed it 6 years ago to be used for designs with hidden scrollbar, and then the behaviour makes more sense – vsync Sep 16 '20 at 16:18

7 Answers7

136

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

aloisdg
  • 16,342
  • 4
  • 73
  • 80
Hussein
  • 40,778
  • 25
  • 110
  • 143
  • 2
    Exactly why the -10 constant? Is it the size of the arrows in scrollbar? – BrunoSalvino Apr 29 '11 at 18:21
  • 8
    @bruno Scroll happens when it's reaches 10px before end of page and not necessary the very end of the page. It's not necessary to have it, but it gives greater control to define at what point page should scroll. – Hussein Apr 29 '11 at 19:04
  • 3
    Is it possible to adopt it to fixed DIV instead of page? – Mark Vital Oct 20 '12 at 23:48
  • @Hussein thanks this is simple and nice , I can simply call my ajax on the above code – kobe Mar 13 '13 at 05:16
  • Great stuff! I had to make a minor modification for larger scroll area triggers. Basically I set a trigger to prevent continuous appends until the last append was successful. Answer here: http://stackoverflow.com/a/18090897/337903 – Nick Aug 06 '13 at 21:35
  • Aren't `$(document).height()` and `$(window).height()` the same? – Dmitri Zaitsev Apr 17 '14 at 17:16
  • How does this handle loading e.g if I used this to load images? – Shaun Moore Sep 16 '20 at 11:29
26

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.

Nick
  • 8,822
  • 6
  • 41
  • 65
  • I also had to add pagination code to mine to complete the effect. Not hard, but something to note. – thekingoftruth Sep 26 '13 at 06:27
  • I used this method. Its works fine. Thanks. But at the end of the page flickering occurs. It is the last record of the DB. But when user try to load more, page is flickering. How to overcome this? – Prageeth Liyanage Jul 21 '18 at 12:19
10

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/

Hawkee
  • 1,967
  • 21
  • 20
2
$(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

venkatesh
  • 23
  • 5
  • 1
    While this answer is probably correct and useful, it is preferred if you [include some explanation along with it](http://meta.stackexchange.com/q/114762/159034) to explain how it helps to solve the problem. This becomes especially useful in the future, if there is a change (possibly unrelated) that causes it to stop working and users need to understand how it once worked. Thanks! – Hatchet Mar 31 '16 at 14:53
1

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 */
                }
            });
        });
Vansuita Jr.
  • 1,493
  • 14
  • 16
1

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>
Mojtaba
  • 145
  • 1
  • 10
  • This is really useful. Don't underestimate this answer just because it is not the TOP answer. It is working just right and it is really fast. – mkdavor Aug 29 '20 at 12:59
0

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

John
  • 6,143
  • 2
  • 35
  • 56