Arnold
Arnold

Reputation: 495

How to do infinite scrolling with javascript only without jquery

I wish to implement infinite scrolling with javascript and without jquery.

I am new to javascript.

After searching all over the net, I have this code.

<!DOCTYPE html><html lang="en"><head><title>scrolling</title>
<style>
.page {height: 900px;border:solid 1px #ccc}
</style>
</head>
<body>

<div id="scrollcontent">

<div class="page"></div>

</div>

<script>

//########################
function getScrollXY() {
var scrOfX = 0, scrOfY = 0;
if( typeof( window.pageYOffset ) == 'number' ) {
    //Netscape compliant
    scrOfY = window.pageYOffset;
    scrOfX = window.pageXOffset;
} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
    //DOM compliant
    scrOfY = document.body.scrollTop;
    scrOfX = document.body.scrollLeft;
} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
    //IE6 standards compliant mode
    scrOfY = document.documentElement.scrollTop;
    scrOfX = document.documentElement.scrollLeft;
}
return [ scrOfX, scrOfY ];
}

function getDocHeight() {
var D = document;
return Math.max(
    D.body.scrollHeight, D.documentElement.scrollHeight,
    D.body.offsetHeight, D.documentElement.offsetHeight,
    D.body.clientHeight, D.documentElement.clientHeight
);
}

document.addEventListener("scroll", function (event) {
if (getDocHeight() == getScrollXY()[1] + window.innerHeight) 
{ 
  var oldcontent = document.getElementById('scrollcontent');
  oldcontent.innerHTML = oldcontent.innerHTML + '<div class="page">new content loaded</div>';
  document.getElementById("scrollcontent").innerHTML=oldcontent.innerHTML;

}
});
</script>
</body>
</html>

However, this code works only when the scrollbar touches the bottom.

I wish it to work when the user is 100 pixels from the bottom. (or near the bottom)

I also need the code to work in most of the modern browsers, mobile devices etc.

Also, is there any way to improve this code? Please suggest.

If there are any errors in the code, please correct.

Thank you

Upvotes: 9

Views: 23090

Answers (6)

Vishaa
Vishaa

Reputation: 31

I used scrollHeight, scrollTop and clientHeight attribute of the element to find whether the scroll hit the bottom. Here is my code. I hope it helps.

Click here for more information.

Image describing scrollHeight, scrollTop and clientHeight

enter image description here

Example

<html>
<head>
<title>Infinite Scroll</title>
</head>
<body>
  <h3>Infinite Scroll Example</h3>
  <div id="scrollContent" style="overflow-y: scroll; height: 100px; width: 500px">
    <div style="height: 300px; background-color: red">
    </div>
  <div>
</body>

<script type="text/javascript">
  document.addEventListener('DOMContentLoaded',function () {
    var elm = document.getElementById('scrollContent');
    elm.addEventListener('scroll',callFuntion);

    function callFuntion(){
      var scrollHeight = elm.scrollHeight;
      var scrollTop = elm.scrollTop;
      var clientHeight = elm.clientHeight;

      if(scrollHeight-scrollTop == clientHeight){
        elm.innerHTML += '<div style="height: 300px; background-color: blue"> New Element Added </div>' ;
      }
    }

  });
</script>

</html>

Upvotes: 2

Jose Greinch
Jose Greinch

Reputation: 458

For achieving that behaviour you don't need JQuery or a JQuery plugin. You just need Pure Css OR Css + Javascript, it depends on the % you want to support

but... DON'T use onScroll: you can do all that just with Vanilla Javascript and the IntersectionObserver API.

All you need to do is place elements and listen for when they become available in the screen. You can accomplish that with a few javascript & html lines and it's much more performant than listening for scroll events in the browsers

I recently put together an article check it here about this

Upvotes: 0

Vasil Popov
Vasil Popov

Reputation: 1258

Why whout jQuery? Some of the native properties like window.outerHeight actually can return not accurate results on some browsers. jQuery fixes that so you can rely that the methods you use returns the same results on any browser and is enough fast to use it.

Here is a very simple way to achieve the infinite scroll without any performance impact:

$(window).on('scroll', function() {
    var threshold = 120;
    if (window.pageYOffset > 0 && window.pageYOffset + $(window).outerHeight(false) >= $(document).outerHeight(false) - threshold) {
        // call your infinite scroll callback, like infiniteScrollDebounced($('#mytable'))
    }
}).scroll();

Notes: the condition in the if clause is intentionally like this, so if the user does not scroll, it will not calculate after window.pageYOffset > 0 and also get into the if (some micro-optimizations ;) ). The zero can be replaced with 20 or 100, so this is the threshold after the site will try to check if the user scrolls and need to do something about it.

I use debounce to postpone the real call to load data (usually websites load data when infinite scrolls), demo: https://davidwalsh.name/function-debounce

So I have this method:

var infiniteScrollDebounced = _.debounce(function($table) {
    var params = $table.data('table-params');
    // Don't request any more if we have reached the end
    if (params.end)
        return;

    params.page++;
    params.append = true;

    GridHelper.reload($table, null, params);
}, 100, true);

My table have data attached to hold the current progress (page, sorting, filtering, etc) and this data is retrieved and passed into the query, so I get properly ordered and filtered results every time. GridHelper.reload() function handles the request and updates the params of the table when the data arrives (the new params are part of the response).

Upvotes: 0

Zach Saucier
Zach Saucier

Reputation: 25954

I use requestAnimationFrame instead of listening for scroll. I also added a throttle based on time so it doesn't overwork our page and batched the element additions:

var numElementsToAdd = 10,
    offsetForNewContent = 20;

function checkInfiniteScroll(parentSelector, childSelector) {
  var lastDiv = document.querySelector(parentSelector + childSelector),
      lastDivOffset = lastDiv.offsetTop + lastDiv.clientHeight,
      pageOffset = window.pageYOffset + window.innerHeight;

  if(pageOffset > lastDivOffset - offsetForNewContent ) {
    for(var i = 0; i < numElementsToAdd; i++) {
      var newDiv = document.createElement("div");
      newDiv.innerHTML = "my awesome new div";
      document.querySelector(parentSelector).appendChild(newDiv);
    }
    checkInfiniteScroll(parentSelector, childSelector);
  }
};

var lastScrollTime = Date.now(), 
    checkInterval = 50;

function update() {
  requestAnimationFrame(update);

  var currScrollTime = Date.now();
  if(lastScrollTime + checkInterval < currScrollTime) {
    checkInfiniteScroll("#scroll-content", "> div:last-child");
    lastScrollTime = currScrollTime;
  }
};

update();
  #scroll-content > div {
      background: #c0c0c0;
      height: 40px;
      margin-bottom: 5px;
  }
<div id="scroll-content">
    <div>test div</div>
</div>

Demo

Upvotes: 2

webpapaya
webpapaya

Reputation: 809

first of all i don't think that you have to support netscape and ie6 anymore. So with that in mind I created following script

document.addEventListener("scroll", function (event) {
    checkForNewDiv();
});

var checkForNewDiv = function() {
    var lastDiv = document.querySelector("#scroll-content > div:last-child");
    var lastDivOffset = lastDiv.offsetTop + lastDiv.clientHeight;
    var pageOffset = window.pageYOffset + window.innerHeight;

    if(pageOffset > lastDivOffset - 20) {
        var newDiv = document.createElement("div");
        newDiv.innerHTML = "my awesome new div";
        document.getElementById("scroll-content").appendChild(newDiv);
        checkForNewDiv();
    }
};

also see jsfiddle

Upvotes: 27

Zafar
Zafar

Reputation: 3434

What about replacing this line of code:

if (getDocHeight() == getScrollXY()[1] + window.innerHeight)

with the following:

if (getDocHeight() - 20 <= getScrollXY()[1] + window.innerHeight) 

Where 20 is the number how much pxs from bottom you want the trigger to execute.

Fiddle

Upvotes: 3

Related Questions