I'm implementing lazy loading functionality for images, which require an AJAX call to a REST backend.

I'm using the scroll and resize events of window to detect whether the image element comes into the viewport:

$(window).on('resize scroll', function() {
          $('img[data-imageloaded=false]').each(function() {
              if ($(this).isInViewport()) {
                  //xhrLoadImage($(this).data("userid"), $(this));

There are in total 16 images in the DOM with data-imageloaded=false, but I only scroll to one at a time to see the effect. In every case, the alert() is triggered twice for each element that enters the viewport.

Also using this to detect the visibility of the image element:

$.fn.isInViewport = function() {
    var elementTop = $(this).offset().top,
        elementBottom = elementTop + $(this).outerHeight(),
        viewportTop = $(window).scrollTop(),
        viewportBottom = viewportTop + $(window).height();

    return elementBottom > viewportTop && elementTop < viewportBottom;

I tried many things, but it keeps happening.

1 Answers

Ziv Weissman On Best Solutions

The issue is that scroll event is fired continuously during scroll event, and if you don't deal with that in your isInViewport function, it will run more than you expect.

Because I am not sure what is your structure of the imgs (do they take full height of viewPort?) if not then probably the condition is met more than once during scroll.

You can try one of the following:

  • Use a "scrollStop" event like so:

    // Setup isScrolling variable
    var isScrolling;
    // Listen for scroll events
    window.addEventListener('scroll', function ( event ) {
      // Clear our timeout throughout the scroll
      window.clearTimeout( isScrolling );
      // Set a timeout to run after scrolling ends
      isScrolling = setTimeout(function() {
        // Your code goes here!
        console.log( 'Scrolling has stopped.' );
      }, 66);
    }, false);

Credit to code here

What this code will do is simple- during scroll event, the interval will always get cleared, except the last time scroll event is fired.

  • Handle "wasThisImageLoaded" of some sort in your function (its good only if you don't have too much images) - by a dictionary of bool where the key is your URL