4
votes

How to prevent jQuery $('body').load('something.php'); from changing any DOM till all the content from something.php (including images,js) is fully loaded

-Lets say some actual content is:

Hello world

And something.php content is:

image that loads for 10 seconds
20 js plugins

After firing .load() function nothing should happen, till images an js files are fully loaded, and THEN instantly change the content.

some preloader may appear, but its not subject of question.

[edit]----------------------------------------------------------------------

My solution for that was css code (css is loaded always before dom is build) that has cross-browser opacity 0.

.transparent{
    -moz-opacity: 0.00;
    opacity: 0.00;
    -ms-filter:"progid:DXImageTransform.Microsoft.Alpha"(Opacity=0);
    filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0);
    filter:alpha(opacity=0);
}

And it prevent from bad flickr of content usually but not always. Now its possible to detect somehow that content is loaded by jQuery ajax and apply some show timeout and so on. But in fact question is still open.

To make now a little more simple example for that question:

How to begin changing DOM after $('body').load('something.php') with 3000ms delay after clicking the link that fire .load('something.php') function? (Browser should start downloading instantly, but DOM changing has to be initiated later)

4
Is it a requirement that the content be loaded, or can there just be the appearance of loading. Meaning is it ok to hide the content until it is finished loading even though it exists in the document already?Quentin Engles

4 Answers

3
votes

Use .get instead and assign the contents in the success callback:

$.get('something.php', function(result) {
    $('body').html(result);
});
1
votes

There are some implementation details you may have to solve yourself, but here's a rough solution:

  1. Don't use .load() directly. It can't be changed to wait for all images to load.

  2. Use $.get() to fetch the HTML into a variable, let's call it frag.

  3. Use $(frag).find('img').each(fn) to find all images and dump each this.src inside a preloader.

    var images = [], 
    $frag = $(frag),
    loaded = 0;
    
    function imageLoaded()
    {
        ++loaded;
        // reference images array here to keep it alive
        if (images.ready && loaded >= images.length) {
            // add $frag to the DOM
            $frag.appendTo('#container');
        }
    }
    
    $frag.find('img').each(function() {
        var i = new Image();
        i.onload = i.onerror = imageLoaded;
        i.src = this.src;
    
        images[images.length] = i;
    });
    
    // signal that images contains all image objects that we wish to monitor
    images.ready = true;
    

    Demo

  4. Once all images are loaded, append the earlier frag to the DOM using $frag.appendTo('#container').

0
votes

Here is a quick proof of concept that loads relevant images before inserting an HTML fragment into the DOM: http://jsfiddle.net/B8B6u/5/

You can preload the images using the onload handler to trigger iterations:

var images = $(frag).find('img'),
loader = $('<img/>');

function iterate(i, callback) {
    if (i > 0) {
        i--;
        loader.unbind("load");
        loader.load(function() {
            iterate(i, callback);
        });
        loader.attr('src', images[i].src);
    }else{
        callback();
    }
}

iterate(images.length,function(){
    $('#container').html(frag);
});

This should work, since each image is loaded after the previous one has finished loading.

0
votes

Have you tried this?

$(function(){$('body').load('something.php')});

Edit: I just realized you are actually wanting to wait for the stuff to load before it get's placed in the body.

Here are three links to similar questions.

Preloading images with jQuery

Is it possible to preload page contents with ajax/jquery technique?

Preloading images using PHP and jQuery - Comma seperated array?

You can probably adapt those to scripts too.

This might work too.

  $.ajax({
    'url': 'content.php',
    'dataType': 'text',
    'success': function(data){
        var docfrag = document.createDocumentFragment();
        var tmp = document.createElement('div'), child;
        //get str from data here like: str data.str
        tmp.innerHTML = str;
        while(child = tmp.firstChild){
            docfrag.appendChild(child);
        }
        $('body').append(docfrag);
    }
  });

It's a longer way of doing what Shadow Wizard suggests, but it will probably work. Hm. Never mind. Jack's answer looks the best. I'll wait a while and if no one likes my answer I'll delete it.

Edit: It looks like appending to documentfragments can do http requests. Any script using createDocumentFrament may benefit from preloading.

In this question they want no http requests even though that's what createDocumentFragment is doing: Using documentFragment to parse HTML without sending HTTP requests.

I can't be sure if this is true for all browsers or just when the console.log is run, but it could be a good option for preloading if this behavior is universal.