skip to Main Content

I am using jQuery.Lazy() Plugin with ASP.NET Core Razor Pages and Bootstrap 4 app to retrieve 2 lists from the DB via AJAX (see photo). Everything is working great except for one thing: on a mobile device, I can’t figure out how to delay the retrieval/display of Content Data 2 List until the user scrolls down far enough in the browser so that Title 2/content is in their view port. The problem is non-existent on desktops (since the lists are displayed side-by-side and both need to be retrieved), but on a mobile device I don’t want to retrieve the Content Data 2 List if the user never scrolls down far enough to see it.

enter image description here

When the page first loads, both of the titles are displayed along with a small data area with a spinner. Using AJAX, I retrieve the data, hide the spinner, and then display the retrieved data in it’s place. My over-simplified HTML is:

<div class="col-sm-12 col-lg-6 lazy" data-loader="lazyAJAX1">
    <div class="col">
        <label class="">Title 1</label>
    </div>

    <div class="col">
        <div class="">
            <div class="lp-spinner mt-4 mb-4">
            </div>
        </div>
        <div id="Content1List" class="col-12">
        </div>
    </div>
</div>

<div class="col-sm-12 col-lg-6 lazy" data-loader="lazyAJAX2">
    <div class="col">
        <label class="">Title 2</label>
    </div>

    <div class="col">
        <div class="">
            <div class="lp-spinner mt-4 mb-4">
            </div>
        </div>
        <div id="Content2List" class="col-12">
        </div>
    </div>
</div>

And the related JQuery is:

$(".lazy").Lazy({
    scrollDirection: 'vertical',
    effect: 'fadeIn',
    visibleOnly: true,
    bind: 'event',
    threshold: 0,
    lazyAJAX1: function () {
        loadAJAX1Partial();
    },
    lazyAJAX2: function () {
        loadAJAX2Partial();
    }
});

After playing with it for a while, I believe the problem is with the data-loaders. Specifically, data-loader="lazyAJAX2" because it is initially displayed in the user’s view port on page load, and therefore automatically retrieves the Content Data 2 List. What I want is for Lazy() to retrieve Content Data 1 List first (which will push the Title 2 content down and out of user’s view port), and then enable/activate Lazy() for Content Data 2 List so that when the user scrolls down far enough to reach Title 2, the Content Data 2 List will be retrieved. I hope that makes sense.

I was contemplating using addClass() to try and get around this, but maybe someone with more .Lazy() experience has a better idea on how to do this.

Thanks for any suggestions/help in advance… 🙂

2

Answers


  1. Chosen as BEST ANSWER

    After some trial and error, I found a solution to my dilemma. Building on what @eisbehr suggested, the secret lies within the DOM refresh.

    The problem is: when the first Content Data 1 List is retrieved via loadAJAX1Partial(), Content Data 2 List is also called/retrieved asynchronously via loadAJAX2Partial(). Depending on the data (size and time taken to return from the server), either of these 2 lists could return in any order. Using what @eisbehr suggested doesn't guarantee the sequence, nor does wrapping the calls in async/await (at least I was not able to constantly get it to work).

    So what is the answer? Using setTimeout() or requestAnimationFrame() and sequencing the retrieval as @eisbehr suggested.

    There is a really good article about DOM and how it refreshes the contents in the browser (see When DOM Updates Appear to Be Asynchronous), but essentially you need to give the browser time to update/refresh Content Data 1 List on screen so that Lazy can do it's magic.

    So in my first AJAX call (loadAJAX1Partial()), on success: (after the list is retrieved), I simply call: setTimeout(loadAssetLists, 500) to loadAssetLists() BUT give it 500ms (1/2 second) to allow for the browser screen to refresh before initializing 'Lazy':

    function loadAssetLists() {
        $(".lazy").Lazy({
            scrollDirection: 'vertical',
            effect: 'fadeIn',
            visibleOnly: true,
            bind: 'event',
            threshold: 0,
            lazyAJAX2: function () {
                loadAJAX2Partial();
            },
            lazyAJAX3: function () {
                loadAJAX3Partial();
            }
            // Chain additional AJAX calls here, if needed
        });
    };
    
    loadAJAX1Partial();

    Allowing the screen to refresh BEFORE Lazy is initialized displays the Content Data 1 List, thereby pushing the Content Data 2 List viewport down. And that seems to work consistently.

    Notice also that once the viewport is moved down, you can easily chain multiple loads (i.e. loadAJAX2Partial(), loadAJAX3Partial(), etc.) and everything works as expected.

    And the great thing is: when the user fully displays the page (by scrolling partially down to retrieve all the AJAX data), clicks to a new page, and then clicks the 'Back button, all the 'Lazy' functionality works as expected.

    I hope this solution and explanation is helpful to others, because I cannot be the only one who has faced this issue... :)


  2. I would think, the problem is, that on your approach, both tables will be requested at the same time, because they initially have no content and therefore are very small. When the user scrolls down he will trigger both loads with a high probability, because there are only headlines.

    If you want to only load the second table after first has been loaded, a easy way would be to use two instances of Lazy. Like shown below. It’s untested but I think you get the idea.

    $("#table1").Lazy({
      tableLoader: function() {
        if (loadAJAX1Partial()) {
          $("#table2").Lazy({
            tableLoader: function() {
              loadAJAX2Partial()
            }
          });
        }
      }
    });
    <div id="table1" class="col-sm-12 col-lg-6" data-loader="tableLoader">
      <div class="col">
        <label class="">Title 1</label>
      </div>
      <div class="col">
        <div>
          <div class="lp-spinner mt-4 mb-4"></div>
        </div>
        <div id="Content1List" class="col-12"></div>
      </div>
    </div>
    
    <div id="table2" class="col-sm-12 col-lg-6" data-loader="tableLoader">
      <div class="col">
        <label class="">Title 2</label>
      </div>
      <div>
        <div>
          <div class="lp-spinner mt-4 mb-4"></div>
        </div>
        <div id="Content2List" class="col-12"></div>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search