Loaded jQuery html content - check if images are loaded and displayed

I have a logic of tabs that load html templates inside a wrapper. This works great, but I have included animation, height

tab wrapper animation when switching tabs.

The problem is this: when the template contains <img src="/some-image.png">

, the callback function is $('#tab-content').load('template-url', function() {...})

sometimes executed before the browser shows the images. And my animation is not working correctly.

Sample code (jsFiddle):

var currentHeight = $contentHolder.height();

$contentHolder.load(path, function() {
    $contentHolder.stop();

    function animateHeight() {
        var loadedContentHeight = $contentHolder.css('height', 'auto').height();
        $contentHolder.height(currentHeight);
        $contentHolder.animate({
            height: loadedContentHeight
        }, 800, 'linear');
    }
    animateHeight();
});

      

I tried to set a small timeout but it doesn't work every time. If I set more than 300ms timeout, it looks like the tabs are changing too slowly.

I tried to animate on startup $('img').load(function() {})

but no luck.

This error occurs most often when the web page is fully refreshed and each time the content of each tab is loaded for the first time.

+3


source to share


2 answers


The image event load

is broken. To know when images are loaded, you will need to see the DOM for changes. Then on every change you have to get all the new images and add an event onload

from the callback to them . To check every element every time as soon as they have been loaded, you can mark them as such by adding, for example, a property data-loaded="true"

.




One way to listen for DOM changes is with the MutationObserver event. This is supported by all modern browsers and IE11 .

The best supported solution (IE9 and up) can be found in this answer: Detect DOM changes . I won't repeat it here (but it's included in the demo below).




Whenever the DOM changes, you first check the images without the attribute data-loaded

that is already loaded (this can happen when the image is still in the browser cache) by checking element.complete

. If so, run the callback function and add an attribute to it.

If .complete

not, add an event to them onload

that also triggers a callback after it's loaded.

In your case, you only want to execute a callback when all images are loaded, so I added a check if there are still images with no attribute data-loaded

. If you remove this if clause, your callback will be triggered after each image is loaded.

// Observe the DOM for changes
observeDOM(document.body, function(){ 
    checkNewImages();
});

var checkNewImages = function() {
    var images = $('img:not([data-loaded]').each(function() {
        addImageLoadedEvent( this );
    });
}

var addImageLoadedEvent = function(img) {
    if (img.complete) {
        onImageLoaded(img);
    } else {
        $(img).on('load', function() {
            onImageLoaded(this);   
        });
    }
}

// The callback that is fired once an element is loaded
var onImagesLoaded = function(img) {
    $(img).attr('data-loaded', 'true');

    if($('img:not([data-loaded])').length === 0) {

        // YourCallbackHere();

    }
}

      

DEMO: fire event on all uploaded images

+1


source


You can call the function animateHeight

as every image of the loaded HTML is loaded. You can expand this selection if you have other objects such as videos.

// Call animateHeight as each image loads
var items = $('img', $contentHolder);
items.bind('load', function(){ 
    animateHeight();
});

      



Demo updated: http://jsfiddle.net/jxxrhvvz/1/

+1


source







All Articles