jQuery, how to preload images and be notified when images are loaded? - javascript

i am still new to all the Javascript stuffs and i have to be honest that i have not yet experimented anything concerning my question.
I would like to know if there is a way or a plugin with jQuery to preloaded multiples images and call a function when the images are loaded?

You can use the load event for images, but they have a number of cross browser issues (it depends on what platforms you're targeting).
var allImgs = $("#container img").filter(function() { return ! this.complete; });
var allImgsLength = allImgs.length;
allImgs.on("load", function() {
if (--allImgsLength) {
// Images have loaded.
}
});
If you don't mind including a plugin, there is waitForImages, (disclaimer: written by me) which handles this relatively nicely. :)
You'd use it like...
$("#container").waitForImages(function() {
// Images have loaded.
});
If you don't want to use jQuery at all, you can adapt the first example. If you're only targeting modern browsers...
var allImgs = [].filter.call(document.querySelectorAll("#container img"),
function(img) {
return ! img.complete;
});
var allImgsLength = allImgs.length;
[].forEach.call(allImgs, function(img) {
img.addEventListener(function() {
if (--allImgsLength) {
// Images have loaded.
}
});
});
If you had to support old browsers...
var allImgs = document.getElementById("container").getElementsByTagName("img");
var allImgsLength = allImgs.length;
var i;
var eventCallback = function() {
if (--allImgsLength) {
// Images have loaded.
}
};
for (i = 0; i < allImgsLength; i++) {
if (allImgs[i].complete) {
allImgsLength--;
}
if (allImgs[i].addEventListener) {
allImgs[i].addEventListener("load", eventCallback);
} elseif (allImgs[i].attachEvent) {
allImgs[i].attachEvent("onload", eventCallback);
} else {
allImgs[i].onload = eventCallback;
}
}

Related

JS custom caching function?

I'd like to initially load a "Caching" function for my Chrome app, then run the actual code, like so:
function preloader(){
hideDOM();
loadSpinner();
for(var i=0;i<x;i++)
caching (loading resources)...
}
function startAPP(){
showDOM();
stopSpinner();
loadAPP();
}
So what I need is the preloader first, then when the "for" loop ends, load the startAPP.
Here is a proof of concept that I cobbled together: (there might be bugs)
function preload_resources(callback) {
var images = [
"http://domain/img1.jpg",
"http://domain/img2.jpg",
"http://domain/img3.jpg"
];
// count the number of completed load events
var count = 0;
function done() {
count += 1;
if (count === images.length) { // all images loaded
callback();
}
}
// make a hidden div;
var div = document.createElement("div");
div.style.display = "none";
document.body.appendChild(div);
// add images to DOM
images.forEach(function (image_url) {
var img = document.createElement("img");
img.src = image_url;
// attach load event
img.addEventListener("load", done);
div.appendChild(img);
});
}
hideDOM();
loadSpinner();
preload_resources(function () {
showDOM();
stopSpinner();
loadAPP();
});
It loads images, in theory you can load anything you want.

Image Preloader Getting Stuck in IE8

I've searched high and low for a solution to this problem, extremely grateful to anyone who can shed some light.
Below is a simplified version of a function used to preload 25 images. It works fantastically well in IE9-10 and in Chrome.
In IE8 it gets partway through loading the images (e.g. 10/25) then just stops. If I then refresh the browser it will continue to load images, taking ~3 refreshes to complete. This should not be necessary!
On the odd occasion it does succeed in loading all images in one go. I tried to avoid using .load() as I've read it can be problematic in IE yet here I am just the same! I also tried using different images to rule out the image format as the cause.
I'm looking for either a fix to the below code or a better solution if someone has one.
Many thanks.
function loadAllImages() {
var imgArray = [ //image SRCs stored in array
'imgsrc01.jpg',
'imgsrc02.jpg',
'imgsrc03.jpg',
...
'imgsrc25.jpg'];
var noFinalImg = imgArray.length - 1;
var i = -1;
var waitTime = 10000;
if (imgArray.length === 0) {
return;
} else {
loadImage();
};
function loadImage() {
i++;
var url = imgArray[i];
var img = new Image();
var timer;
img.src = url;
img.id = "thumb" + i;
// image loaded
if (img.complete || img.readyState === 4) {
//Call image loaded function
console.log(i + "/" + noFinalImg);
//equivalent to loop next
if (i !== noFinalImg) {
loadImage();
};
// image not loaded
} else {
// handle 404 using setTimeout set at waitTime
timer = setTimeout(function () {
if (i !== noFinalImg) {
loadImage();
};
$(img).unbind('error load onreadystate');
}, waitTime);
$(img).bind('error load onreadystatechange', function (e) {
clearTimeout(timer);
if (e.type !== 'error') {
//Call image loaded function
console.log(i + "/" + noFinalImg);
};
if (i !== noFinalImg) {
loadImage();
};
});
};
};
};

GetElementbyID fails to fire

From my reading here I would expect this code to work, but it doesn't. I have tried two ways to add click events to a button called "lonext". Neither work. I'm not sure why this might be?
window.onload = function() {
var goSC = function() { //go to the sucess criteria section
document.getElementsByClassName("guidance1").style.display = "none";
document.getElementsByClassName("guidance2").style.display = "";
alert("button clicked");
//first try
document.getElementById("lonext").addEventListener("click", function() {
goSC();
}, false);
//second try
document.getElementById("lonext").onclick = goSC;
}
The getElementsByClassName returns an NodeList because you could have many elements in your DOM with the same class, not a single element.
So:
var goSC = function() {
var guidance1 = document.getElementsByClassName("guidance1");
for (var i = 0; i < guidance1.length; i++) {
guidance[i].style.display = "none";
}
var guidance2 = document.getElementsByClassName("guidance2");
for (var i = 0; i < guidance2.length; i++) {
guidance[i].style.display = "";
}
alert("button clicked");
});
window.onload = function() {
document.getElementById("lonext").onclick = goSC;
};
which if you used jQuery could be simplified to:
$(function() {
$('#lonext').click(function() {
$('.guidance1').hide();
$('.guidance2').show();
});
});
I would also strongly recommend you using a javascript debugging tool such as FireBug or Chrome Developer toolbar to inspect your javascript code and see potential errors with it. The Console tab will contain valuable information about possible errors in your javascript code.

How to detect if some text box is changed via external script?

I have some jQuery plugin that changes some elements, i need some event or jQuery plugin that trigger an event when some text input value changed.
I've downloaded jquery.textchange plugin, it is a good plugin but doesn't detect changes via external source.
#MSS -- Alright, this is a kludge but it works:
When I call boxWatcher() I set the value to 3,000 but you'd need to do it much more often, like maybe 100 or 300.
http://jsfiddle.net/N9zBA/8/
var theOldContent = $('#theID').val().trim();
var theNewContent = "";
function boxWatcher(milSecondsBetweenChecks) {
var theLoop = setInterval(function() {
theNewContent = $('#theID').val().trim();
if (theOldContent == theNewContent) {
return; //no change
}
clearInterval(theLoop);//stop looping
handleContentChange();
}, milSecondsBetweenChecks);
};
function handleContentChange() {
alert('content has changed');
//restart boxWatcher
theOldContent = theNewContent;//reset theOldContent
boxWatcher(3000);//3000 is about 3 seconds
}
function buttonClick() {
$('#theID').value = 'asd;lfikjasd;fkj';
}
$(document).ready(function() {
boxWatcher(3000);
})
try to set the old value into a global variable then fire onkeypress event on your text input and compare between old and new values of it. some thing like that
var oldvlaue = $('#myInput').val();
$('#myInput').keyup(function(){
if(oldvlaue!=$('#myInput').val().trim())
{
alert('text has been changed');
}
});
you test this example here
Edit
try to add an EventListner to your text input, I don't know more about it but you can check this Post it may help
Thanks to #Darin because of his/her solution I've marked as the answer, but i have made some small jQuery plugin to achieve the same work named 'txtChgMon'.
(function ($) {
$.fn.txtChgMon = function (func) {
var res = this.each(function () {
txts[0] = { t: this, f: func, oldT: $(this).val(), newT: '' };
});
if (!watchStarted) {
boxWatcher(200);
}
return res;
};
})(jQuery);
var txts = [];
var watchStarted = false;
function boxWatcher(milSecondsBetweenChecks) {
watchStarted = true;
var theLoop = setInterval(function () {
for (var i = 0; i < txts.length; i++) {
txts[i].newT = $(txts[i].t).val();
if (txts[i].newT == txts[i].oldT) {
return; //no change
}
clearInterval(theLoop); //stop looping
txts[i].f(txts[i], txts[i].oldT, txts[i].newT);
txts[i].oldT = $(txts[i].t).val();
boxWatcher(milSecondsBetweenChecks);
return;
}
}, milSecondsBetweenChecks);
}

setInterval with other jQuery events - Too many recursions

I'm trying to build a Javascript listener for a small page that uses AJAX to load content based on the anchor in the URL. Looking online, I found and modified a script that uses setInterval() to do this and so far it works fine. However, I have other jQuery elements in the $(document).ready() for special effects for the menus and content. If I use setInterval() no other jQuery effects work. I finagled a way to get it work by including the jQuery effects in the loop for setInterval() like so:
$(document).ready(function() {
var pageScripts = function() {
pageEffects();
pageURL();
}
window.setInterval(pageScripts, 500);
});
var currentAnchor = null;
function pageEffects() {
// Popup Menus
$(".bannerMenu").hover(function() {
$(this).find("ul.bannerSubmenu").slideDown(300).show;
}, function() {
$(this).find("ul.bannerSubmenu").slideUp(400);
});
$(".panel").hover(function() {
$(this).find(".panelContent").fadeIn(200);
}, function() {
$(this).find(".panelContent").fadeOut(300);
});
// REL Links Control
$("a[rel='_blank']").click(function() {
this.target = "_blank";
});
$("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
$("#content").fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
}
}
This works fine for a while but after a few minutes of the page being loaded, it drags to a near stop in IE and Firefox. I checked the FF Error Console and it comes back with an error "Too many Recursions." Chrome seems to not care and the page continues to run more or less normally despite the amount of time it's been open.
It would seem to me that the pageEffects() call is causing the issue with the recursion, however, any attempts to move it out of the loop breaks them and they cease to work as soon as setInterval makes it first loop.
Any help on this would be greatly appreciated!
I am guessing that the pageEffects need added to the pageURL content.
At the very least this should be more efficient and prevent duplicate handlers
$(document).ready(function() {
pageEffects($('body'));
(function(){
pageURL();
window.setTimeout(arguments.callee, 500);
})();
});
var currentAnchor = null;
function pageEffects(parent) {
// Popup Menus
parent.find(".bannerMenu").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
subMenu: $(this).find("ul.bannerSubmenu"),
handlerIn: function() {
this.subMenu.slideDown(300).show();
},
handlerOut: function() {
this.subMenu.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
parent.find(".panel").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
content: panel.find(".panelContent"),
handlerIn: function() {
this.content.fadeIn(200).show();
},
handlerOut: function() {
this.content.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
// REL Links Control
parent.find("a[rel='_blank']").each(function() {
$(this).target = "_blank";
});
parent.find("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
var content = $("#content");
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
content.fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
pageEffects(content);
}
}
Thanks for the suggestions. I tried a few of them and they still did not lead to the desirable effects. After some cautious testing, I found out what was happening. With jQuery (and presumably Javascript as a whole), whenever an AJAX callback is made, the elements brought in through the callback are not binded to what was originally binded in the document, they must be rebinded. You can either do this by recalling all the jQuery events on a successful callback or by using the .live() event in jQuery's library. I opted for .live() and it works like a charm now and no more recursive errors :D.
$(document).ready(function() {
// Popup Menus
$(".bannerMenu").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find("ul.bannerSubmenu").slideDown(300);
} else {
$(this).find("ul.bannerSubmenu").slideUp(400);
}
});
// Rollover Content
$(".panel").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find(".panelContent").fadeIn(200);
} else {
$(this).find(".panelContent").fadeOut(300);
}
});
// HREF Events
$("a[rel='_blank']").live("click", function(event) {
var target = $(this).attr("href");
window.open(target, "_blank");
event.preventDefault();
});
$("a[rel='share']").live("click", function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
setInterval("checkAnchor()", 500);
});
var currentAnchor = null;
function checkAnchor() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn(200);
$("#content").fadeOut(200).html(data).fadeIn(200);
$("#load").fadeOut(200);
});
}
}
Anywho, the page works as intended even in IE (which I rarely check for compatibility). Hopefully, some other newb will learn from my mistakes :p.

Categories