Saturday, September 24, 2016

Wait for Something - When Javascript onload event is not enough

Recently I needed to take actions on certain element of the DOM that would be created by other script and I also needed to take actions when images contained in these element where completed loaded.

The onload event seemed not fitting completely this purpose so I wrote this small function.
  • The function simply check the existence of the element (or any other condition) and when the condition is met, it execute the callback function.
  • If the condition is not met, it sets a timer to call itself again.
  • If after certain number of attempts the condition is still not met, the function stops.
Here some example on the usage.

Case 1

Waiting for an image to load:
凸.waitForSomething({
 name: 'Wait for width of newImage3',
 element: document.getElementById('newImage3'),
 verbose: true,
 waitFor: function(obj) {return obj.element.width > 0},
 thenDo: function(obj) {obj.element.style.background = 'lightgreen'},
});
In this case the condition is met when the img element has a width that is bigger than 0.

Case 2

Waiting for an image to ba added in the DOM and than to be loaded These are two of the many way it can be achieved:

Case 2.1

凸.waitForSomething({
 name: 'Wait for width of newImage2',
 verbose: true,
 waitFor: function(obj) {
  var $element = document.getElementById('newImage2');
  if ($element && (document.getElementById('newImage2').width > 0)) {
   obj.element = $element;
   return true;
  } else {
   return false;
  }
 },
 thenDo: function(obj) {
  obj.element.style.border = '2px solid brown';
  obj.element.style.background = 'gold';
 },
});
Here the condition check first the existence of the element and then that the element width would be grater than 0 The other way is

Case 2.2

凸.waitForSomething({
 name: 'Wait for width of newImage1',
 verbose: true,
 waitFor: function() {return document.getElementById('newImage1');},
 thenDo: function(obj) {
  var $element = obj.waitFor();
  $element.style.border = '2px solid blue';
  凸.waitForSomething({
   element: $element,
   waitFor: function(obj) {return obj.element.width > 0;},
   thenDo: function(obj) {
    var $element = obj.element;
    $element.style.background = 'lightblue';
   },
   name: 'Wait for width of newImage1',
   verbose: true,
  });
 },
});
Here there is a first call to 凸.waitForSomething to check the existence of the element. Once the element is created, another call to 凸.waitForSomething wait for the images to have a width larger than 0

Example

Note: See at the console of this page to see the log of 凸.waitForSomething

Code

This is the script:
var 凸 = (function(凸) {
"use strict";
var id = 0,
waitForSomething = function (obj) {
obj = obj || {};
obj.c = obj.c || 1;
obj.cMax = obj.cMax || 10;
obj.verbose = obj.verbose || false;
obj.id = obj.id === undefined ? id++ : obj.id;
var log = function(text, text2) {
text2 = text2 || (obj.c === 1 ? 'START' : ' ');
if (obj.verbose)
console.log(text2 + 'id:' + obj.id + ' #' + obj.c + ' [' + obj.name + '] ' + text + ' [' + obj.waitFor(obj) + ']');
};
if (obj.c > obj.cMax) {
log('giving up', 'END');
} else {
if( obj.waitFor(obj) ) {
log('will execute thenDo', 'END');
return obj.thenDo( obj );
}
else {
var ms = Math.pow( 2, obj.c ) * 2 + 50;
log('will try again in ' + ms + 'ms');
obj.c++;
setTimeout(function () {
waitForSomething(obj);
}, ms);
}
}
};
凸.waitForSomething = waitForSomething;
return 凸;
}(凸 || {}));

No comments :

Post a Comment