Wait to execute code until after AJAX called image renders - javascript

I am trying to run some code that grabs the width and height of a div after it is loaded and filled with an image from an AJAX call.
The div is 0x0 until the image is placed so checking the dimensions before pretty much breaks everything.
I have tried .load() (Doesn't work because this is an AJAX call). I also tried the imagesLoaded js plugin. Here is what I have right now:
alert('outside;')
function startBubbles(){
alert('inside');
var space = new DisplaySpace($('#bubbleWrap').height(), $('#bubbleWrap').width());
var count = 1;
alert(space.getHeight());
var delay = (function(){
var timer = 0;
return function(afterResize, ms){
clearTimeout (timer);
timer = setTimeout(afterResize, ms);
};
})();
var spawnInterval = self.setInterval(function(){
var aBubble = new Bubble(count, space);
count++
aBubble.spawnimate(aBubble);
setTimeout(function() {aBubble.popBubble(aBubble)},Math.floor((Math.random()*30000)+10000));
}, 500);
});
My alerts all fire before the image is visible, then my 'space' object still has height and width of 0.
bubbleWrap is a div inside the loading zone that contains the image in question. I realize I could probably but a manual delay in here to solve the problem MOST of the time - however that doesn't seem optimal. What am I missing?
I'm now implementing the load of this particular state like this:
History.Adapter.bind(window,'popstate',function(){
var state = History.getState();
state = 'target='+state.data.state;
$.get('contents.php', state, function(data){
if(state == 'target=bubbles'){
$('#loading_zone').html(data).waitForImages(startBubbles());
}
else{
$('#loading_zone').html(data);
}
});
});
Unfortunately, on page reload, the height ends up as only 10. Everything seems great when I just navigate away and come back, though. Any thoughts?

I have a plugin that could do this nicely.
Simply call it after you inject the new HTML.
// Assume this function is the callback to the *success*.
function(html) {
$("#target").html(html).waitForImages(function() {
// All descendent images have now loaded, and the
// containing div will have the correct dimensions.
});
};

Related

How to monitor an image source for fully loaded status

I am loading a large number of images into a dynamic DIV and I am using a preloader to get the images.
imageObj = new Image();
imageObj.src = imgpath + imgname;
Each of these events creates a GET that I can see and monitor in Firebug.
If I know the name and path of an image, can I watch the relevant XMLHttpRequest to see if the GET has completed?
I do not want to rely on (or use) .onload events for this process.
The pseudo would look something like this...
if (imageObj.GET = 'complete')
Has anyone had any experience of this?
EDIT 1
Thanks to the help from Bart (see below) I have changed my image preloader to store an array of the image objects...
function imagePreLoader(imgname) {
images[imgnum] = new Image();
images[imgnum].src = imgpath + imgname;// load the image
imgnum ++;
}
And then, after all my other functions have run to build the content DIVs, I used the image.complete attribute in the following...
var interval = setInterval(function () {
imgcount = imgnum - 1; // because the imgnum counter ++ after src is called.
ok = 1;
for (i=0; i<imgcount; i++) {
if (images[i].complete == false){
ok = 0;
}
}
if (ok == 1) {
clearInterval(interval);
showIndexOnLoad();
}
}, 1000);
This waits until all the images are complete and only triggers the showIndexOnLoad() function when I get the 'ok' from the interval function.
All images now appear as I wanted, all at once with no additional waits for the GETs to catch up.
Well done Bart for putting me on to the image.complete attribute.
You can watch the complete property of the image to see if the image is fully loaded or not.
Here's an example.
http://jsfiddle.net/t3esV/1/
function load (source) {
var img = new Image();
img.src = source;
console.log('Loading ' + source);
var interval = setInterval(function () {
if (img.complete) {
clearInterval(interval);
complete(img);
}
}, 400);
};
function complete(img) {
console.log('Loaded', img.src);
document.body.appendChild(img);
};
Note: This example fails to clear the interval when something goes wrong and complete is never set to true.
Update
I wrote a simple jQuery.preload plugin to take advantage of the image.complete property.
This is a very interesting problem, and I am afraid there is no actual solution to this. The load event for images is when the image is being rendered and the browser knows the width and height of it.
What you would be after would be a tag-applicable readystatechange event. Alas, only IE allows you to bind those to non-document elements, so this is not an option.
There are a bunch of plug-ins that allow you to go around it, as well. One pretty hot one is https://github.com/desandro/imagesloaded , which has the added advantage of dealing with all the browser differences very efficiently. It, however, still relies on the load event (and I am pretty sure this is the only way to start doing what you want to do).

Working on Infinite Load in jQuery and can't get the Load function to load only once

I'm working on an Infinite Load (e.g. Lazy Load) type functionality here is the function so far:
$(window).scroll(function() {
var ScrollPosition = $(window).scrollTop() + $(window).height();
var LoadMorePosition = $(document).height()-100;
if( ScrollPosition == LoadMorePosition ) {
console.log('loading more');
loadMoreItems();
}
});
It's working for the most part except for that the loadMoreItems function is called 20-30 times once the person scrolls to the threshhold.
I was thinking a setTimeout type thing might work but on second thought I realized that it would only work if the Ajax content loaded fast enough (which isn't guaranteed).
What I need is a way to detect if they hit the threshold and then call the function only once until they hit the scroll threshold again.
You could do it like this:
var loadOnce = function(fn) {
var loadedPages = {};
return function(page) {
var key = 'p'+page;
if (typeof loadedPages[key] === 'undefined') {
fn.apply(fn, arguments);
loadedPages[key] = true;
}
};
};
var loader = loadOnce(function(page) {
/* Ajax Request */
});
// Will only fire the ajax request once:
loader(1);
loader(1);
loader(1);
loader(1);
I was thinking a setTimeout type thing might work but on second thought I realized that it would only work if the Ajax content loaded fast enough (which isn't guaranteed).
Then don't rely on a timeout, instead reset the flag on the success\complete of the AJAX request.
AJAX call's success part should set load more content flag, so you do not load more if you do not have more.
And for scrolling, set timeout to detect when user stops scrolling and then execute showing loading gif and do ajax, on success, hide the gif, and load more :D
$(window).scroll(function(){
clearTimeout(scrolled);
scrolled = setTimeout(function(){
//Your function when user stops scrolling
}, 100);
});

Javascript bookmarklet/iFrame to auto-refresh loaded page if no activity detected within set timeframe?

I have a browser-based application that I use at work (as effectively all corporate apps are now browser-based for obvious reasons) that has an annoyingly short session timeout. I'm not sure precisely what the session timeout is set to, but it's something along the order of 5-10 minutes.
Inevitably whenever I have to use it the session has timed out, I enter the information into the app, submit it, and then the page loads with a brand new session without any of the information actually being passed on - all I get is a new session. I then have to re-enter the information and submit it again in order to have it actually pull up what I want. Of course, I could first refresh the page and then enter the info, but I never know if the session is timed out or not and occasionally it runs painfully slowly so this is a waste of time. Our development team's inability to foresee that little things like this are not only annoying, but also end up costing us a ton of money when you consider the amount of time lost (I work for a VERY large corporation) just waiting for the blasted thing to reload and then having to re-enter the submitted information if a pre-refresh was forgotten as it usually is happens to be beyond me. At some point I'm hoping to become the liaison between the programmers and our customer service body.
Anyway, I digress.
What I'm looking to do is this: I'd like to create a Javascript bookmarklet or something that will automatically refresh whatever page it happens to be on if activity isn't detected within a certain timeframe. This timeframe will be a bit short of whatever I end up figuring out what the session timeout is. Basically I just want to make the page reload itself every, say, five minutes if there hasn't been activity within that period. (I don't want it to refresh out of the blue because the time is up while I'm in the middle of using the app, the only time it should do the auto-refresh is if the app page has been sitting idle)
Can this be done with a Javascript bookmarklet? Should I program a page "wrapper" of sorts that loads the application page within an iFrame or something of the sort? The app site that I use has many subpages, and I'd prefer for it to refresh whatever page I happen to be on at the time if the auto-refresh timeout occurs. Of course, if that isn't possible I'd accept it just reloading the main site page if that's not easily possible since if I've been out of the app long enough for the timeout to happen then I likely don't need to still be on whatever account/page I was on at the time.
Hopefully I've explained myself well enough. The logic is simple - if no activity detected withing x amount of time, refresh the current page is the gist of it.
Thank you, my StackOverflow brethren, yet again for your assistance.
-Sootah
Since I have no ability to influence the coding of the page itself, I've got to have the most simple solution possible. A bookmarklet that times the last refresh/pageload and then refreshes the same page if the timeout is reached would be perfect.
If that's not possible, then if I could write a simple page that I could run from the local computer that'd do the same function by loading the page in a frame or something that'd also be acceptable.
EDIT 10/3/11 7:25am MST
Since I work graves and an odd schedule at work (and this site, unfortunately, being blocked there since it's considered a 'forum' - I work in finance, they're overly cautious about information leakage) before I award the bounty, does one of these event detectors detect the last time the page loaded/? Something like document.onload or whatnot. I'm thinking that setting the timer from the last time the page was loaded is going to be the simplest and most effective approach. My mouse may move over the browser that I have the site open in inadvertently while working on other things, and if the timer resets because of that without me actually having interacted with the site in such a way that a page loads/reloads then the session times out.
This is the bookmarklet code #1 for you, set up to FIVE seconds. Change time to what you like more.
javascript:
(function () {
var q = null;
function refresh() { window.location.reload(); }
function x() { clearTimeout(q); a(); }
function a() { q = setTimeout( refresh, 5000 ); }
document.body.onclick = x;
document.body.onmousemove = x;
document.body.onmousedown = x;
document.body.onkeydown = x;
}())
p.s.: would have been nicer to include eventListeners, but i suppose you need to support IE8, too, so i replaced them with inline events, - if you DON'T need IE8, use code #2:
javascript:
(function () {
var q = null;
function refresh() { window.location.reload(); }
function x() { clearTimeout(q); a(); }
function a() { q = setTimeout( refresh, 5000 ); }
document.body.addEventListener( "click", x, false );
document.body.addEventListener( "mousemove", x, false );
document.body.addEventListener( "mousedown", x, false );
document.body.addEventListener( "keydown", x, false );
}())
edit: in response to comments, here is code #3 with pulling, instead of refreshing page. Yet, despite advices to use iframe, i decided it might be desirable to not execute scripts on that page, so we will use img instead:
javascript:
(function () {
var q = null;
var u = window.location.href;
var i = document.createElement('img');
i.style = "width: 1px; height: 1px;";
document.body.appendChild(i);
function refresh() {
i.src = "";
i.src = u;
x();
}
function x() { clearTimeout(q); a(); }
function a() { q = setTimeout( refresh, 5000 ); }
var evs = ['click', 'mousemove', 'mousedown', 'keydown'];
for( var j = 0; j < evs.length; j++) {
document.body['on'+evs[j]] = x;
}
}())
Create a bookmark and place the code below in the "url" value. Please note that you should change the values of "sessiontimeout" and "checkinterval". They're both in milliseconds.
javascript:(function(){var lastmove = new Date().valueOf(),sessiontimeout=10000,checkinterval=1000;document.onmousemove = function(e){lastmove= new Date().valueOf();};timer = setInterval( function() {var differential = (new Date().valueOf() - lastmove);if (differential > sessiontimeout) {var iframe = document.getElementById("bkmrkiframerefresher");if (iframe) { document.getElementsByTagName("body")[0].removeChild(iframe);} iframe = document.createElement("iframe");iframe.setAttribute("src", "/");iframe.setAttribute("width", 0);iframe.setAttribute("height", 0);iframe.setAttribute("style", "width:0;height:0;display:none;");iframe.setAttribute("id", "bkmrkiframerefresher");document.getElementsByTagName("body")[0].appendChild(iframe);lastmove = new Date().valueOf();} }, checkinterval);})();
This is a bookmarklet that will inject the code below in the page. I tested the bookmarklet in Chrome. It worked on multiple sites except stackoverflow, it seems that they block framing for security reasons. Before you leave your desk, open the website which session you wanna keep alive, then click the bookmarklet on it. Once you're back, refresh the page in order to get rid of the running timers.
The formatted (and commented) code is:
<script type="text/javascript">
// last time the mouse moved
var lastmove = new Date().valueOf();
var sessiontimeout=10000;
var checkinterval=1000;
// reset the last time the mouse moved
document.onmousemove = function(e){
lastmove= new Date().valueOf();
}
// check periodically for timeout
timer = setInterval( function() {
var differential = (new Date().valueOf() - lastmove);
if (differential > sessiontimeout) {
var iframe = document.getElementById("bkmrkiframerefresher");
// iframe already exists, remove it before loading it back
if (iframe) {
document.getElementsByTagName("body")[0].removeChild(iframe);
}
// alert("more than 10 secs elapsed " + differential);
// create an iframe and set its src to the website's root
iframe = document.createElement("iframe");
iframe.setAttribute("src", "/");
iframe.setAttribute("width", 0);
iframe.setAttribute("height", 0);
iframe.setAttribute("id", "bkmrkiframerefresher");
iframe.setAttribute("style", "width:0;height:0;display:none;");
document.getElementsByTagName("body")[0].appendChild(iframe);
// reset counter.
lastmove = new Date().valueOf();
}
}, checkinterval);
</script>
Stefan suggested above that you need no logic besides polling. The edited code is the following:
<script type="text/javascript">
var pollInterval=1000;
timer = setInterval( function() {
var iframe = document.getElementById("bkmrkiframerefresher");
// iframe already exists, remove it before loading it back
if (iframe) {
document.getElementsByTagName("body")[0].removeChild(iframe);
}
// create an iframe and set its src to the website's root
iframe = document.createElement("iframe");
iframe.setAttribute("src", "/");
iframe.setAttribute("width", 0);
iframe.setAttribute("height", 0);
iframe.setAttribute("id", "bkmrkiframerefresher");
iframe.setAttribute("style", "width:0;height:0;display:none;");
document.getElementsByTagName("body")[0].appendChild(iframe);
}
}, pollInterval);
</script>
This code only reload the page once
Here is a bookmarklet(inspired by Kaj Toet's pseudo code), tested in Chrome and Safari, change the timeout value with the var time at the start of the line
Onliner:
javascript:var time = 500; var timeoutFunc = function(){location.reload(true);};timeout = setTimeout(timeoutFunc,time);document.onmousemove = function() {clearTimeout(timeout);timeout = setTimeout(timeoutFunc,time); };
Code
//The time in milliseconds before reload
var time = 500;
//The function that is called when the timer has reached 0
var timeoutFunc = function() {
location.reload(true);
};
//start the timer
timeout = setTimeout(timeoutFunc,time);
//restart the timer if the mouse is moved
document.onmousemove = function() {
clearTimeout(timeout);
timeout = setTimeout(timeoutFunc,time);
};
pseudocode
timeout = settimeout("call",200);
document.onmousemove = function() { timeout = new timeout("call",200); }
function call() {
document.refresh();
}
like this?

How to check the status each 10 seconds with JavaScript?

I have a server (mysite.com/status), which returns number of active tasks (just a single integer).
How can I check number of active tasks each 10 seconds with JavaScript and show user something like:
Number of remaining tasks: XXX
And, if number of tasks is 0, then I should load another page.
Make a function set a new timeout calling itself.
function checkTasks(){
// Make AJAX request
setTimeout(checkTasks, 10000);
}
checkTasks(); // Start task checking
with jQuery for AJAX functions... (untested code)
setInterval(function(){
$.get('http://example.com/status',function(d){
// where there is html element with id 'status' to contain message
$('#status').text('Number of remaining tasks: '+d)
if(d == 0){
window.location = '/another/page'
}
})
},10000)
I have thought of different approach, without any AJAX. As you just need to show simple plain data, just use <iframe> to show that dynamic data then with simple JS "reload" the frame every 10 seconds.
HTML would be:
Number of remaining tasks: <iframe id="myFrame" src="mysite.com/status"></iframe>
And the JavaScript:
window.onload = function() {
window.setTimeout(ReloadTime, 10000);
};
function ReloadTime() {
var oFrame = document.getElementById("myFrame");
oFrame.src = oFrame.src;
window.setTimeout(ReloadTime, 10000);
}
Live test case, using time for the same of example.
With some CSS you can make the frame look like part of the text, just set fixed width and height and remove the borders.
setInterval(function(elem){ // here elem is the element node where you want to display the message
var status=checkStatus(); // supposing that the function which returns status is called checkStatus
if(status == 0){
window.location = '/another/page'
}
else {
elem.innerHTML="Number of remaining tasks:"+status;
}
},10000)
Using the javascript library jquery, you can set a repeating infinite loop.
That gets the data from a page and then sets the inner html of an element.
http://jsfiddle.net/cY6wX/14/
This code is untested
edit: demonstration updated
Also I did not use the jquery selector for setting the value in case you do not want to use jquery.

Loading message

Searching for a js script, which will show some message (something like "Loading, please wait") until the page loads all images.
Important - it mustn't use any js framework (jquery, mootools, etc), must be an ordinary js script.
Message must disappear when the page is loaded.
Yeah an old-school question!
This goes back to those days when we used to preload images...
Anyway, here's some code. The magic is the "complete" property on the document.images collection (Image objects).
// setup a timer, adjust the 200 to some other milliseconds if desired
var _timer = setInterval("imgloaded()",200);
function imgloaded() {
// assume they're all loaded
var loaded = true;
// test all images for "complete" property
for(var i = 0, len = document.images.length; i < len; i++) {
if(!document.images[i].complete) { loaded = false; break; }
}
// if loaded is still true, change the HTML
if(loaded) {
document.getElementById("msg").innerHTML = "Done.";
// clear the timer
clearInterval(_timer);
}
};
Of course, this assumes you have some DIV thrown in somewhere:
<div id="msg">Loading...</div>
Just add a static <div> to the page, informing user that the page is loading. Then add window.onload handler and remove the div.
BTW, what’s the reason of this? Don’t users already have page load indicators in their browsers?
You should do async ajax requests for the images and add a call back when it's finished.
Here's some code to illustrate it:
var R = new XMLHttpRequest();
R.onreadystatechange = function() {
if (R.readyState == 4) {
// Do something with R.responseXML/Text ...
stopWaiting();
}
};
Theoretically you could have an onload event on every image object that runs a function that checks if all images is loaded. This way you don´t need a setTimeOut(). This would however fail if an image didn´t load so you would have to take onerror into account also.

Categories

Resources