Loading images with jQuery and handling of events for showing loading spinners

This tutorial tells you how to load images with jQuery and how to handle events in order to show and hide loading spinners. I have been using this approach since at least 2009 without any issues. It should even work on older browsers like IE7. Of course, the example should run on any modern browser as well. You can use this code in your own projects, but make sure not to forget the attribution...

I have implemented two examples of how to use the loadImage(...) API (see below). The listeners are used to show a loading spinner and to hide it (sometimes referred to as "loading icon" or "busy indicator"). For the overlay functionality I use basic CSS and HTML. However, the loading spinners I display and hide via callback functions work on Chrome, Safari, Firefox and IE9+, IE 7/8 or lower is not supported because I am using rgba in my CSS (I did not check other browsers). But there is also an easy way to display the loading spinner in a cross browser enabled way. To demonstrate this I have also added a separate example, please check the code below for details. The examples should be self explanatory. You could even extend the API the way you want, i.e. allowing to pass an already existing image element or just the id of that image element (I did not add this to the API to keep it simple).

The basic idea behind the scenes of the loadImage() API is:

  • Use the JavaScript Image object
  • Listen for the beforeLoad event to display the loading spinner
  • Listen for the complete event to remove the loading spinner
  • Listen for the load event to display the loaded image
  • Listen for the error event to display a simple error message
  • Trigger load in case the image is loaded from the cache

Please do not get confused about the wording I have used here. I wrote this tutorial down to make it accessible for everybody because I know there are many people out there struggling with the best way to load images with JavaScript. There are many ways to implement the event handlers and performance improvements of the handlers are possible. Although maybe not relevant for this tutorial, if you want to learn what browser reflow is then visit this. By the way: don't forget to leave me a comment or donation if you like this tutorial.

Are you looking for a solution that runs without jQuery? Or in other words: are you looking for a way to load images with plain old, native JavaScript? This is covered in my other tutorial: Loading images with native JavaScript and handling of events for showing loading spinners

Enough words, here is the full code of how you can load images with jQuery:

loadImagesWithJQuery.html (demo)
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>DEMO: Loading images with jQuery and handling of events for showing loading spinners</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >
        <meta http-equiv="X-UA-Compatible" content="IE=edge" >

        <!-- <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> -->
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

        <style>
            .imageContainer {
                position:relative; height:200px; width:150px; border:1px solid black; margin-top:20px;
            }

            .imageContainer.horizontal{
                display:inline-block; margin-left: 10px;
            }
            
            /* Attention: our loading spinner is not optimized for IE 7/8 or below, but it works with IE9+ */
            .loadingSpinner {
                position: absolute;
                z-index: 1000;
                top: 0;
                left: 0;
                height: 100%;
                width: 100%;                            
                background: rgba( 255, 255, 255, .8 ) 
                            url('/assets/img/nabisoft/tutorials/loading-spinner-red.gif') 
                            50% 50% 
                            no-repeat;
            }
            
            /* Cross Browser Loading Spinner */
            .crossBrowserLoadingSpinner {
                position: absolute;
                z-index: 1000;
                top: 0;
                left: 0;
                height: 100%;
                width: 100%;
                opacity: 0.8;
                background-color: white;
                               
                /* IE 8 */
                -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
                /* IE 7 */
                filter: alpha(opacity=80);
                zoom: 1;
            }
            
            .loadingSpinnerImage {
                position: absolute;
                z-index: 1001;
                top: 0;
                left: 0;
                height: 100%;
                width: 100%;
                background: transparent url('/assets/img/nabisoft/tutorials/loading-spinner-red.gif') 50% 50% no-repeat;               
            }
            
        </style>

        <script>

            $(function () {
                "use strict";

                /**
                 * Utility function for detecting if an image could be loaded or not
                 *
                 * @author Nabi Zamani
                 * @copyright Nabi Zamani 2009
                 * @license Released under the MIT license
                 * @requires jQuery
                 * @param {String} opts.imgUrl       The url from where the image is to be loaded
                 * @param {Function} opts.beforeLoad A function to be called the loading is executed
                 * @param {Function} opts.complete   A function to be called when the loading has been completed
                 * @param {Function} opts.success    A function to be called when the image has been loaded successfully
                 * @param {Function} opts.error      A function to be called in case image could not be loaded
                 * @param {Object} opts.customData   A custom object that is passed to the event listeners 
                 * @see http://www.nabisoft.com/tutorials/javascript/loading-images-with-jQuery-and-handling-of-events-for-showing-loading-spinners                 
                 */
                $.loadImage = function (opts) {
                    var loadedImage = new Image();
                    if (typeof opts !== "object" || opts === null){
                        window.console && console.log("loadImage(): Please pass valid options");
                        return;
                    }
                    typeof opts.beforeLoad === 'function' && opts.beforeLoad({imgUrl:opts.imgUrl, customData:opts.customData});
                    $(loadedImage).one('load', function(){
                        var oData = {success:true,url:opts.imgUrl,imageElem:loadedImage, customData:opts.customData};
                        typeof opts.complete === 'function' && opts.complete(oData);
                        typeof opts.success === 'function' && opts.success(oData);
                    }).one('error', function(){
                        var oData = {success:false,url:opts.imgUrl,imageElem:loadedImage, customData:opts.customData};
                        typeof opts.complete === 'function' && opts.complete(oData);
                        typeof opts.error === 'function' && opts.error(oData);
                    }).attr('src', opts.imgUrl).each(function(){
                        if(this.complete){  //cached image
                            $(this).trigger('load');
                        }
                    });
                };

                $("#loadImageBtn").click(function(){

                    /******************************************************************************
                     * EXAMPLE 1
                     *****************************************************************************/
                    (function () {
                        var oOpts, jqImageUrlInput, jqImageContainer;

                        jqImageUrlInput  = $("#imageUrl");
                        jqImageContainer = $("#imageContainer");

                        oOpts = {
                            imgUrl  : jqImageUrlInput.val(),
                            beforeLoad : function (oEvent){
                                $("<div class='loadingSpinner'></div>").appendTo(jqImageContainer);
                            },
                            complete : function (oEvent){
                                jqImageContainer.find(".loadingSpinner:first").remove();
                            },
                            success : function(oEvent){
                                jqImageContainer.html(oEvent.imageElem);    //place the image somewhere
                            },
                            error : function(oEvent){
                                jqImageContainer.html("ERROR");
                            }
                        };
                        $.loadImage(oOpts);
                    })();

                    /******************************************************************************
                     * EXAMPLE 2
                     *****************************************************************************/
                    (function () {
                        var i, oOpts, jqImageContainer, fBeforeLoadingCallback, fCompleteCallback, 
                            fSuccessCallback, fErrorCallback;

                        fBeforeLoadingCallback = function (oEvent) {
                            $("<div class='loadingSpinner'></div>").appendTo(oEvent.customData.jqContainer);
                        };
                        fCompleteCallback  = function (oEvent) {
                            oEvent.customData.jqContainer.find(".loadingSpinner:first").remove();
                        };
                        fSuccessCallback  = function (oEvent) {
                            oEvent.customData.jqContainer.html(oEvent.imageElem);   //place the image somewhere
                        };
                        fErrorCallback = function (oEvent) {
                            oEvent.customData.jqContainer.html("ERROR");
                        };

                        for (i=1; i <= 5; i++){
                            jqImageContainer = $("#imageContainer"+i);

                            oOpts = {
                                imgUrl     : "http://lorempixel.com/150/200/?v="+i,
                                beforeLoad : fBeforeLoadingCallback,
                                complete   : fCompleteCallback,
                                success    : fSuccessCallback,
                                error      : fErrorCallback,
                                customData : {
                                    jqContainer : jqImageContainer
                                }
                            };
                            $.loadImage(oOpts);
                        }
                    })();
                });
            });
        </script>

    </head>

    <body>
        
        <h1>DEMO: Loading images with jQuery and handling of events for showing loading spinners</h1>
    
        <h2>1. Calling the API for a single image URL</h2>
        <div>
            <input id="imageUrl" type="text" value="http://lorempixel.com/150/200/" style="width:300px;"/>
            <button id="loadImageBtn">Load Image</button>
        </div>
        <div id="imageContainer" class="imageContainer"></div>

        <br/><br/>

        <h2>2. Passing data to callback functions (Static URLs used)</h2>
        <div id="imageContainer1" class="imageContainer horizontal"></div>
        <div id="imageContainer2" class="imageContainer horizontal"></div>
        <div id="imageContainer3" class="imageContainer horizontal"></div>
        <div id="imageContainer4" class="imageContainer horizontal"></div>
        <div id="imageContainer5" class="imageContainer horizontal"></div>
        
        <br/><br/>
        
        <h2>3. Static Example: Cross Browser Loading Spinner</h2>
        <div id="imageContainer" class="imageContainer">
            <img src="http://lorempixel.com/150/200/">
            <div class="crossBrowserLoadingSpinner">
                <div class="loadingSpinnerImage"></div>
            </div>
        </div>
        
    </body>
    
</html>

Have a look at the Demo to see this example in action. Hint: Only the image at the top is loaded from the url derived from the input field.

Comments