SkillAgentSearch skills...

Jquery.mobile.lazyloader

jquery.mobile.lazyloader is a proper jQuery Mobile Widget for lazy loading listviews with AJAX calls to a server-side resource.

Install / Use

/learn @dcarrith/Jquery.mobile.lazyloader
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

LazyLoader Widget for jQuery Mobile

Official Site: http://dcarrith.github.com/jquery.mobile.lazyloader

Lazyloading (i.e. loading the content as it's needed during a scroll of a listview or similar control) is a great way to optimize the performance of any app that contains a list of 50 or more items. With the LazyLoader Widget for jQuery Mobile, you can easily lazyload any listview without having to write a bunch of custom code to accomplish it. The idea is to enable the widget on index pageinit, and then track instances of pages that contain listviews that can all be independently lazyloaded with the main widget instance.

Note: This is only the client-side part of the lazyloading solution. It requires a server-side resource that returns a simple JSON formatted string. Details and examples can be found below.

Requirements

  • jQuery 1.7.x (although, jQuery 1.6.4 may work fine - it just hasn't been tested - and, the examples are tailored to jQuery 1.7.x)
  • jQuery Mobile 1.1.x (1.0.x might work fine - it just hasn't been tested)
  • jquery.json2html-3.0.js - if using json2html JSON transform templates
  • ICanHaz.js - if using ICanHaz templates
  • handlebars-1.0.0.beta.6.js - if using standard Handlebars templates
  • handlebars.runtime.js - if using pre-compiled Handlebars templates
  • dust-full-1.0.0.js - if using Dust templates - note: this is the version maintained by LinkedIn
  • dust-core-1.0.0.js - if using pre-compiled Dust templates - note: this is the version maintained by LinkedIn
  • doT.js - if using doT templates (optimized fork of Underscore.js)
  • Server-side code to handle the AJAX requests

Using the LazyLoader widget

First, to use the widget, you must download the main JavaScript file into your JavaScript directory. Then, simply include the widget file after the core jQuery Mobile JavaScript file and the other dependencies:

<script src="includes/js/jquery-1.7.2.min.js"></script>

<!-- Template library or libraries can probably go here -->

<script src="includes/js/jquery.mobile-1.1.0.js"></script>
<script src="includes/js/jquery.mobile.lazyloader.js"></script>

Then, to instantiate the widget instance, add a pageinit for your main page (in my case the main data-role="page" has an id="index"):

$('body').on('pageinit', '#index', function( evt, ui ) {

    // Initialize the lazyloader widget
    $("#index").lazyloader();

    /* Set some default options for the lazyloader
     *   the first three set the timeout value for when the widget should check
     *   the current scroll position relative to page height to decide whether
     *   or not to load more yet.  The showprogress option is to specify the
     *   duration of the fadeIn animation for the lazyloaderProgressDiv.
     */
    $.mobile.lazyloader.prototype.timeoutOptions.mousewheel = 300;
    $.mobile.lazyloader.prototype.timeoutOptions.scrollstart = 700;
    $.mobile.lazyloader.prototype.timeoutOptions.scrollstop = 100;
    $.mobile.lazyloader.prototype.timeoutOptions.showprogress = 100;
});

Now, the rest of this documentation will use examples specific to the application for which this widget was originally developed (www.mpdtunes.com). Using a music app as the model will provide good use-case scenarios to be explained.

For any pages that contain listviews that you want to lazyload, you have to add a pageinit handler such as the one used below for the artists page:

$('body').on('pageinit', '#artists', function(evt, ui) {

    /* Reset the lazy loader instance for the albums page
     *   This resets the widget instance variables for the albums page    
     *   This is done here because the artists page is one level up
     *   from the albums page, so it needs to be reset in case the user
     *   selects a different artist who will have their own albums that
     *   will need to be lazy loaded
     *   
     *   Note: in this example, "reset" is the function and "albums" is
     *      the pageId of the albums page 
     */
    $( "#index" ).lazyloader( "reset", "albums" );

    // Use an automatic threshold that's a function of the height of the viewport
    threshold = $( window ).height();

    // Set up the variable options to pass to the lazyloader reinitialize function
    var options = {   "threshold"   : threshold,
                      "retrieve"    : 20,
                      "retrieved"   : 20,
                      "bubbles"     : true,
                      "offset"      : 0 };

    // Set up the page specific settings to pass to the lazyloader reinitialize function
    var settings = {  "pageId"                : "artists",
                      "templateType"          : "dust",
                      "templateId"            : "artists",
                      "templatePrecompiled"   : true,
                      "mainId"                : "artistsList",
                      "progressDivId"         : "lazyloaderProgressDiv",
                      "moreUrl"               : "/artists/more",
                      "clearUrl"              : "/home/clear_session" };

    // Set up the post parameters to pass to the lazyloader reinitialize function
    var parameters = {  "retrieve"    : options.retrieve,
                        "retrieved"   : options.retrieved,
                        "offset"      : options.offset };

    // Reinitialize the lazyloader so that it correctly handles the listview on the artists page
    $( "#index" ).lazyloader( "reInitialize", options, settings, parameters );
});

Here's an example of how the lazyloader is reinitialized on the albums page. Notice the higher threshold compared to the artists page and the lower retrieve and retrieved values. That is because the albums list items are about twice the height of the artists li items because the albums have album art:

$('body').on('pageinit', '#albums', function(evt, ui) {

    // Use an automatic threshold that's a function of the height of the viewport
    threshold = $( window ).height();

    // Set up the variable options to pass to the lazyloader reinitialize function
    var options = { "threshold"   : threshold,
                    "retrieve"    : 10,
                    "retrieved"   : 10,
                    "bubbles"     : true };

    // Set up the page specific settings to pass to the lazyloader reinitialize function
    var settings = {  "pageId"                : "albums",
                      "templateType"          : "dust",
                      "templateId"            : "albums",
                      "templatePrecompiled"   : true,
                      "mainId"                : "albumsList",
                      "progressDivId"         : "lazyloaderProgressDiv",
                      "moreUrl"               : "/albums/more",
                      "clearUrl"              : "/home/clear_session" };

    // Set up the post parameters to pass to the lazyloader reinitialize function
    var parameters = {  "retrieve"    : options.retrieve,
                        "retrieved"   : options.retrieved,
                        "offset"      : options.offset };

    // Reinitialize the lazyloader so that it correctly handles the listview on the artists page
    $( "#index" ).lazyloader( "reInitialize", options, settings, parameters );
});

What to do when a listview also has a search filter?

When a listvew is being lazy loaded and also has a search filter (which kind of requires all items to be shown so they can be filtered properly) the trick is to just pull the rest of the listview items onfocus to the search filter. Here's an example of how to do that:

$('body').on('focusin', 'input[data-type="search"]', function(evt, ui) {

    // Set the retrieve option to all so it pulls the rest of the items to lazy load
    $( "#index" ).lazyloader( "option", "retrieve", "all" );

    // Refresh the corresponding parameter with the option that was just set
    $( "#index" ).lazyloader( "refresh", "parameter", "retrieve" );

    // Manually make a call to the public version of the _load function and override the default timeout
    $( "#index" ).lazyloader( "loadMore", 0 );
});

Basically, the first line sets the option "retrieve" to the value "all". The refresh method is then called and the "retrieve" parameter is updated with the value of the option that was just set. Then, the loadMore function is called using the internal options and parameters stored for the particular page on which the listview and search filter exist.

What to do when there is a button that manually scrolls the page down (and therefore doesn't use scrollstart, scrollstop or mousewheel)?

It's easy, just call loadMore, which will use whatever options, settings and parameters the lazyloader widget was re-initialized with:

function scrollDown(section) {
    
    // do whatever
    ...

    // Manually make a call to the public version of the _load function
    $( "#index" ).lazyloader( "loadMore" );
}

Explanation of available options:

<table> <tr> <th>Option</th><th>Value</th><th>Purpose</th> </tr> <tr> <td>threshold</td><td>$( window ).height()</td><td>This specifies the threshold in pixels for how close to the bottom of the page should the widget get before making the call to the private function _load. It now defaults to $( window ).height() but can be overridden with a static value or any function of $( window ).height() (e.g. 2 * $( window ).height() if you want)</td> </tr> <tr> <td>retrieve</td><td>20</td><td>This specifies how many items should be retrieved with each lazy loading ajax call</td> </tr> <tr> <td>retrieved</td><td>20</td><td>This specifies the number of items that are initially loaded on the server-side</td> </tr> <tr> <td>bubbles</td><td>true</td><td>This specifies whether or not to calculate the count bubbles in the list item markup that get's loaded dynamically</td> </tr

Related Skills

View on GitHub
GitHub Stars77
CategoryDevelopment
Updated3y ago
Forks18

Languages

JavaScript

Security Score

80/100

Audited on Dec 31, 2022

No findings