jQuery function after .append

Jquery

Jquery Problem Overview


How to call a function after jQuery .append is completely done?

Here's an example:

$("#root").append(child, function(){
   // Action after append is completly done
});

The issue: When a complex DOM structure is appended, calculation of new size of the root element within the append function callback is wrong. Assumptions are that the DOM in still not completely loaded, only the first child of the added complex DOM is.

Jquery Solutions


Solution 1 - Jquery

You've got many valid answers in here but none of them really tells you why it works as it does.

In JavaScript commands are executed one at a time, synchronously in the order they come, unless you explicitly tell them to be asynchronous by using a timeout or interval.

This means that your .append method will be executed and nothing else (disregarding any potential timeouts or intervals that may exist) will execute until that method have finished its job.

To summarize, there's no need for a callback since .append will be run synchronously.

Solution 2 - Jquery

Although Marcus Ekwall is absolutely right about the synchronicity of append, I have also found that in odd situations sometimes the DOM isn't completely rendered by the browser when the next line of code runs.

In this scenario then shadowdiver solutions is along the correct lines - with using .ready - however it is a lot tidier to chain the call to your original append.

$('#root')
  .append(html)
  .ready(function () {
    // enter code here
  });

Solution 3 - Jquery

Well I've got exactly the same problem with size recalculation and after hours of headache I have to disagree with .append() behaving strictly synchronous. Well at least in Google Chrome. See following code.

var input = $( '<input />' );
input.append( arbitraryElement );
input.css( 'padding-left' );

The padding-left property is correctly retrieved in Firefox but it is empty in Chrome. Like all other CSS properties I suppose. After some experiments I had to settle for wrapping the CSS 'getter' into setTimeout() with 10 ms delay which I know is UGLY as hell but the only one working in Chrome. If any of you had an idea how to solve this issue better way I'd be very grateful.

Solution 4 - Jquery

I'm surprised at all the answers here...

Try this:

window.setTimeout(function() { /* your stuff */ }, 0);

Note the 0 timeout. It's not an arbitrary number... as I understand (though my understanding might be a bit shaky), there's two javascript event queues - one for macro events and one for micro events. The "larger" scoped queue holds tasks that update the UI (and DOM), while the micro queue performs quick-task type operations.

Also realize that setting a timeout doesn't guarantee that the code performs exactly at that specified value. What this does is essentially puts the function into the higher queue (the one that handles the UI/DOM), and does not run it before the specified time.

This means that setting a timeout of 0 puts it into the UI/DOM-portion of javascript's event queue, to be run at the next possible chance.

This means that the DOM gets updated with all previous queue items (such as inserted via $.append(...);, and when your code runs, the DOM is fully available.

(p.s. - I learned this from Secrects of the JavaScript Ninja - an excellent book: https://www.manning.com/books/secrets-of-the-javascript-ninja )

Solution 5 - Jquery

I have another variant which may be useful for someone:

$('<img src="http://example.com/someresource.jpg">').load(function() {
    $('#login').submit();
}).appendTo("body");

Solution 6 - Jquery

I came across the same problem and have found a simple solution. Add after calling the append function a document ready.

$("#root").append(child);
$(document).ready(function () {
    // Action after append is completly done
});

Solution 7 - Jquery

Using MutationObserver can act like a callback for the jQuery append method:

I've explained it in another question, and this time I will only give example for modern browsers:

// Somewhere in your app:
var observeDOM = (() => {
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

    return function(obj, callback){
        if( MutationObserver ){
            // define a new observer
            var obs = new MutationObserver(function(mutations, observer){
                if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
                    callback(mutations);
            });
            // have the observer observe foo for changes in children
            obs.observe( obj, { childList:true, subtree:true });

            return obs;
        }
    }
})();

//////////////////
// Your code:

// setup the DOM observer (on the appended content's parent) before appending anything
observeDOM( document.body, ()=>{
    // something was added/removed
}).disconnect(); // don't listen to any more changes

// append something
$('body').append('<p>foo</p>');

Solution 8 - Jquery

I think this is well answered but this is a bit more specific to handling the "subChild_with_SIZE" (if that's coming from the parent, but you can adapt it from where it may be)

$("#root").append(
    $('<div />',{
        'id': 'child'
    })
)
.children()
.last()
.each(function() {
    $(this).append(
        $('<div />',{
            'id': $(this).parent().width()
        })
    );
});

Solution 9 - Jquery

the Jquery append function returns a jQuery object so you can just tag a method on the end

$("#root").append(child).anotherJqueryMethod();

Solution 10 - Jquery

$.when($('#root').append(child)).then(anotherMethod());

Solution 11 - Jquery

For images and other sources you can use that:

$(el).one('load', function(){
	// completed
}).each(function() {
	if (this.complete)
		$(this).load();
});

Solution 12 - Jquery

Cleanest way is to do it step by step. Use an each funciton to itterate through each element. As soon as that element is appended, pass it to a subsequent function to process that element.

    function processAppended(el){
        //process appended element
    }

    var remove = '<a href="#">remove</a>' ;
    $('li').each(function(){
        $(this).append(remove);   
        processAppended(this);    
    });​

Solution 13 - Jquery

I encountered this issue while coding HTML5 for mobile devices. Some browser/device combinations caused errors because .append() method did not reflect the changes in the DOM immediatly (causing the JS to fail).

By quick-and-dirty solution for this situation was:

var appint = setInterval(function(){
	if ( $('#foobar').length > 0 ) {
		//now you can be sure append is ready
		//$('#foobar').remove(); if elem is just for checking
		//clearInterval(appint)
	}
}, 100);
$(body).append('<div>...</div><div id="foobar"></div>');

Solution 14 - Jquery

Yes you can add a callback function to any DOM insertion:
$myDiv.append( function(index_myDiv, HTML_myDiv){ //.... return child })

Check on JQuery documentation: <http://api.jquery.com/append/><br> And here's a practical, similar, example: <http://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_html_prepend_func>

Solution 15 - Jquery

I ran into a similar problem recently. The solution for me was to re-create the colletion. Let me try to demonstrate:

var $element = $(selector);
$element.append(content);

// This Doesn't work, because $element still contains old structure:
$element.fooBar();    

// This should work: the collection is re-created with the new content:
$(selector).fooBar();

Hope this helps!

Solution 16 - Jquery

I know it's not the best solution, but the best practice:

$("#root").append(child);

setTimeout(function(){
  // Action after append
},100);

Solution 17 - Jquery

$('#root').append(child);
// do your work here

Append doesn't have callbacks, and this is code that executes synchronously - there is no risk of it NOT being done

Solution 18 - Jquery

$('#root').append(child).anotherMethod();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid Hor&#225;kView Question on Stackoverflow
Solution 1 - JquerymekwallView Answer on Stackoverflow
Solution 2 - JqueryDaniel - SDS GroupView Answer on Stackoverflow
Solution 3 - JqueryWomiView Answer on Stackoverflow
Solution 4 - JqueryjleachView Answer on Stackoverflow
Solution 5 - JquerymsangelView Answer on Stackoverflow
Solution 6 - JqueryshadowdiverView Answer on Stackoverflow
Solution 7 - JqueryvsyncView Answer on Stackoverflow
Solution 8 - JqueryJames JonesView Answer on Stackoverflow
Solution 9 - JqueryDavidView Answer on Stackoverflow
Solution 10 - JqueryrenatolunaView Answer on Stackoverflow
Solution 11 - JqueryMycelinView Answer on Stackoverflow
Solution 12 - JqueryhitwillView Answer on Stackoverflow
Solution 13 - JqueryPyry LiukasView Answer on Stackoverflow
Solution 14 - JqueryPedro FerreiraView Answer on Stackoverflow
Solution 15 - JquerykralykView Answer on Stackoverflow
Solution 16 - JqueryManvelView Answer on Stackoverflow
Solution 17 - JqueryDavid FellsView Answer on Stackoverflow
Solution 18 - JqueryVivekView Answer on Stackoverflow