Tutorial :How can you get your code to wait for html() and append() functions to complete?



Question:

I'm setting the html of the body element in an iframe to a string str, then I want to access that content on the next line (here just using an alert call to display the content) but the html and append functions haven't completed by the time the alert statement is called.

$(function(){  ....  $("#notes-tab span.add_draft").bind("click", function(e){      var str = '';      $(this).parent().siblings(".tab-content").children(".para").each(function(ind) {          str += $(this).find('div:first').html();      });      var curr = $("#content_rte").contents().find("body").html();      if (curr == ' ' || curr == '<br>') {          $("#content_rte").contents().find("body").html(str);      }      else {          $("#content_rte").contents().find("body").append(str);      }      alert($("#content_rte").contents().find("body").html());  });  });  

And of course neither the html nor the append functions take callbacks.

Could someone tell me how one normally accomplishes waiting for the DOM to be changed before proceeding?


Solution:1

There's really no direct method for waiting other than setting an arbitrary timeout before you attempt to retrieve the HTML. The code to do so would be:

// wait for 250 ms, then try and retrieve contents  setTimeout(function() {      alert($("#content_rte").contents().find("body").html());  }, 250);  

You should try and make the timeout small enough to go unnoticed but large enough to allow for the contents to update, so you could get away with much less than 250ms.


Solution:2

If you are using jQuery you can rely on .closest() to figure out if the element you just created has a parent body tag, and if it does it means it's been added to the DOM. You can write a function such as the following to allow you to actually do something when your element is ready:

callWhenReady: function (selector, callback, scope) {      var self = this;      if ($(selector).closest('body').length) {          callback.call(scope);      } else {          setTimeout(function () {              self.callWhenReady(selector, callback, scope);          }, 1);      }  }  


Solution:3

html and append both call domManip, which is a synchronous method, so alert shouldn't even execute until those calls have completed.

Are you sure that the values you expect are being copied into the locations you expect?


Solution:4

You need to wait for the dom load event so that the iframe has time to finish loading:

$(document).ready(function(){      var str = '<div>HelloWorld</div>';      var curr = $("#content_rte").contents().find("body").html();      if (curr == ' ' || curr == '<br>') {          //$("#content_rte").contents().find("body").html(str);          $("#content_rte").contents().find("body").append(str);      }      else {          $("#content_rte").contents().find("body").append(str);      }      alert($("#content_rte").contents().find("body").html());  });  


Solution:5

you should try $(window).load(function()) rather than document.ready also you could always fire the event after your appends. that way the event(s) will only run once the append has successfully rendered.

the window.load only runs once the dom has loaded and then all content within the dom too.

if that doesnt work for you, then you could always have a setTimeout() run on the document.ready or window.load and put your functions/events in there and it will load after a specific amount of seconds.

you could try:

$(document).ready(function(){    var curr = $("#content_rte").contents().find("body").html();      if (curr == ' ' || curr == '<br>') {          $("#content_rte").contents().find("body").html(str);      }      else {          $("#content_rte").contents().find("body").append(str);      }  });  $(window).load(function(){      alert($("#content_rte").contents().find("body").html());  });  


Solution:6

You need to use $( document ).ready( function( ){ } ) or $( function( ){ } ) but with that iframe's document element.

To do this, you can put your script into the iframe's HTML

theIframeHTMLContent += '<script type="text/javascript" src="jquery.js"></script>' +                          '<script type="text/javascript">' +                            '$( function( ){ alert( "I\'m ready!" ); } );' +                          '</script>';    $( 'body' ).append( '<iframe id="cool"></iframe>' );  $( '#cool' ).html( theIframeHTMLContent );  

Or you can try to do it on the newly appended iframe DOM element itself, but from the parent frame. This is different across browsers, but the following example SHOULD work.

$( 'body' ).append( '<iframe id="cool"></iframe>' )  var theFrame = $( '#cool' )[ 0 ];  var docEl = theFrame.contentDocument || theFrame.contentWindow || theFrame.document;  $( docEl ).ready( function( ){ /* ready stuff */ } );  

Tell me if I'm wrong, like I said, haven't tested this.


Solution:7

I followed the grancalavera's answer, but I used the lengh because my selector already exists in body... so:

var finalLength = $(selector).html().length + data.length;  $(selector).html(data); //or $(selector).append(data);  //...  callWhenReady: function (selector, callback, finalLength, scope) {      var self = this;      if ($(selector).html().length === finalLength) {          callback.call(scope);      } else {          setTimeout(function () {              self.callWhenReady(selector, callback, scope);          }, 1);      }  }  


Solution:8

Try to use .ready(), which is "a way to run JavaScript code as soon as the page's Document Object Model (DOM) becomes safe to manipulate."

$('#yourID').html('new content').ready(function(){      // Do stuffs  });  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »