Browser is not smooth while using jQuery "replaceWith" - javascript

I'm using jQuery replaceWith to update information of my website. Div elements which are returned are small. The function is called after 5 minutes. When I focus on browser, replaceWith function will run but my browser is not smooth and sometime can crash. Which plugin or solution can I use to resolve the problem ?
I used:
$('#hotpost').hide().html(newHtml).fadeIn("slow");
$('#hotpost div.content').hide().replaceWith(newHtml).fadeIn("slow");

I believe you should compile your HTML into a document fragment
using for example, this function
var compileHTML = function (html) {
var div = document.createElement("div");
div.innerHTML = html;
var fragment = document.createDocumentFragment();
while ( div.firstChild ) {
fragment.appendChild( div.firstChild );
}
return fragment
};
before appending your HTML into your new div
like so:
$('#hotpost').hide().html(compileHTML(newHtml)).fadeIn("slow");
Plus I saw that in your code you're usin setInterval which when blurring the window can have unexpected behaviours, you could use this:
(function loop(){
//what you need to do
$('#hotpost').hide().html(compileHTML(newHtml)).fadeIn("slow"); //for example
setTimeout(loop, (18000));
})();
this new loop will wait until the code inside is executed before looping again, rather than executing the code and ("no", says browser, "user is using memory in an other tab")
And when you go back to your page, multiple animations happen at the same time...

Related

Avoid wrong interpretation of source with document.createElement for dynamic sources

I have script that I would like visitors on my website to run when they load a web page. It looks like this:
window.onload = function(){
var pxl=document.createElement('img');
pxl.setAttribute('src', 'http://localhost:8080/getTrackingPixel')
document.body.appendChild(pxl);
}
Most of the times the source returns an image and it works fine. However, sometimes it returns this:
<html><body style="background-color:transparent"></body></html>
And I can't really change the fact that it might sometimes not return an image. How do I change the javascript so that it can handle the html response without any errors? It might be possible for me to predict when it happens though - but I haven't managed to find a good way to request the source and return the html either.
You can achieve it by using the javascript Image object which, unlike the createElement approach, allows you to fetch the src url before inserting the img in the DOM.
The onload event of the Image object won't fire if the loaded content isn't an img.
Here it is :
window.onload = function(){
var pxl = new Image();
pxl.onload = function(){
// is IMG
document.body.appendChild(pxl);
}
pxl.onerror = function(){
// is not IMG
// Meaning in your case : <html><body style="background-color:transparent"></body></html>
}
pxl.src = 'http://localhost:8080/getTrackingPixel';
}
(Note that your code also missed the semicolon ";" line 4)

Using JavaScript or JQuery how do I determine when a DOM element is added to the page?

An external JavaScript adds a DOM element to a page.
Using JavaScript or JQuery how do I determine when this DOM element is added to the page?
You basically have three choices, one of which isn't available on all browsers:
Get a notification from the other script that it's added an element (if it provides one)
Poll (I'd use setTimeout and reschedule each following check on purpose) to see if the element appears. E.g.:
var CHECK_INTERVAL = 100; 100 = 1/10th second, choose appropriate
function checkForElement() {
/* ...check for the element... */
if (/*...you found the element...*/) {
// Do something with it
}
else {
// Check again after a brief pause
setTimeout(checkForElement, CHECK_INTERVAL);
}
}
setTimeout(checkForElement, CHECK_INTERVAL);
Use a mutation observer, which is the replacement for the broken old mutation events. This lets you register a callback to be called on certain mutation events. Support is reasonable but — quelle shock — IE didn't get them until IE11.
If you have access to that external javascript file, you can just call a function in your page from that file just after you add an element. If you don't have this facility or there is not event triggering in between, you can keep on checking existence of such element in a certain interval using javascript setInterval() method.
var chekElement = function (){
// this will rerun function every second
var chekElemRecursiveTimer = setTimeout(chekElement, 1000);
var someElement = $('.someElement');
if (someElement){
alert("its on page!");
clearTimeout(chekElemRecursiveTimer);
}
}
// run function in page or from external js file
chekElement();
another way to checked this
var chekForElement = function (){
var chekElementTimer = setTimeout(chekForElement, 1000);
if ($('.chcekedElementclass').length > 0){
alert("found in page");
clearTimeout(chekElemRecursiveTimer);
}
}
// run function in page or from external js file
chekForElement();

Bug in my lazyload plugin for mootools

I want to implement a plug-in serial download pictures in MooTools. Let's say there are pictures with the img tag inside a div with the class imageswrapper. Need to consistently download each image after it loads the next and so on until all the images are not loaded.
window.addEvent('domready', function(){
// get all images in div with class 'imageswrapper'
var imagesArray = $$('.imageswrapper img');
var tempProperty = '';
// hide them and set them to the attribute 'data-src' to cancel the background download
for (var i=0; i<imagesArray.length; i++) {
tempProperty = imagesArray[i].getProperty('src');
imagesArray[i].removeProperty('src');
imagesArray[i].setProperty('data-src', tempProperty);
}
tempProperty = '';
var iterator = 0;
// select the block in which we will inject Pictures
var injDiv = $$('div.imageswrapper');
// recursive function that executes itself after a new image is loaded
function imgBomber() {
// exit conditions of the recursion
if (iterator > (imagesArray.length-1)) {
return false;
}
tempProperty = imagesArray[iterator].getProperty('data-src');
imagesArray[iterator].removeProperty('data-src');
imagesArray[iterator].setProperty('src', tempProperty);
imagesArray[iterator].addEvent('load', function() {
imagesArray[iterator].inject(injDiv);
iterator++;
imgBomber();
});
} ;
imgBomber();
});
There are several issues I can see here. You have not actually said what the issue is so... this is more of a code review / ideas for you until you post the actual problems with it (or a jsfiddle with it)
you run this code in domready where the browser may have already initiated the download of the images based upon the src property. you will be better off sending data-src from server directly before you even start
Probably biggest problem is: var injDiv = $$('div.imageswrapper'); will return a COLLECTION - so [<div.imageswrapper></div>, ..] - which cannot take an inject since the target can be multiple dom nodes. use var injDiv = document.getElement('div.imageswrapper'); instead.
there are issues with the load events and the .addEvent('load') for cross-browser. they need to be cleaned up after execution as in IE < 9, it will fire load every time an animated gif loops, for example. also, you don't have onerror and onabort handlers, which means your loader will stop at a 404 or any other unexpected response.
you should not use data-src to store the data, it's slow. MooTools has Element storage - use el.store('src', oldSource) and el.retrieve('src') and el.eliminate('src'). much faster.
you expose the iterator to the upper scope.
use mootools api - use .set() and .get() and not .getProperty() and .setProperty()
for (var i) iterators are unsafe to use for async operations. control flow of the app will continue to run and different operations may reference the wrong iterator index. looking at your code, this shouldn't be the case but you should use the mootools .each(fn(item, index), scope) from Elements / Array method.
Anyway, your problem has already been solved on several layers.
Eg, I wrote pre-loader - a framework agnostic image loader plugin that can download an array of images either in parallel or pipelined (like you are trying to) with onProgress etc events - see http://jsfiddle.net/dimitar/mFQm6/ - see the screenshots at the bottom of the readme.md:
MooTools solves this also (without the wait on previous image) via Asset.js - http://mootools.net/docs/more/Utilities/Assets#Asset:Asset-image and Asset.images for multiple. see the source for inspiration - https://github.com/mootools/mootools-more/blob/master/Source/Utilities/Assets.js
Here's an example doing this via my pre-loader class: http://jsfiddle.net/dimitar/JhpsH/
(function(){
var imagesToLoad = [],
imgDiv = document.getElement('div.injecthere');
$$('.imageswrapper img').each(function(el){
imagesToLoad.push(el.get('src'));
el.erase('src');
});
new preLoader(imagesToLoad, {
pipeline: true, // sequential loading like yours
onProgress: function(img, imageEl, index){
imgDiv.adopt(imageEl);
}
});
}());

Dynamically adding HTML with Javascript which has <img> tags. How do I tell when the images are loaded

Lets say I have a div, and want to inject into that div some HTML. The HTML will include 1 or more images.
Is there any way with plain JavaScript or jQuery to determine when the images have loaded?
So if I do the following, can you place an event listener onto a single element to tell when the contents, including images, is ready?:
var html = "<p>Some text <img src='image.jpg' /></p><p>Some more text <img src='image2.jpg' /></p>";
$("div.output").html(html);
The images will be different every time so I cannot preload using JavaScript image object.
One method I'm thinking of doing is running through the HTML with regular expressions or jQuery, finding all image URLs, loop through them and preload each with the image object. When all have been preloaded, then inject the HTML into the output div.
Unless you hook up an onload event to each image before it loads and count them up, there's no easy way to tell when they're all loaded.
Here's a relatively bulletproof method (demo) that uses Deferreds, tested and working in IE 6-9, Chrome 19, and Firefox 3.6-10, Opera 10.10-11.52, Android 4, and iOS 5.
First, we'll write a small jQuery plugin that returns an array of Deferreds for each element in the jQuery collection. Each Deferred will be resolved when the element loads; or rejected if the element fails to load or (optionally) takes longer than timeout seconds.
$.fn.loaded = function(opts) {
var o = $.extend({timeout:10000}, opts) // Merge default options with supplied options
, r = []; // Return value
this.each(function() {
var dfd = new $.Deferred(), el = $(this), to;
if (o.timeout) to = setTimeout(function() {
done();
dfd.reject();
}, o.timeout);
el.bind('load.dfdl', function() {
done();
dfd.resolve();
}).bind('error.dfdl', function() {
done();
dfd.reject();
});
function done() { // internal clean-up
clearTimeout(to);
el.unbind('.dfdl');
}
r.push(dfd.promise());
});
return r;
};
The timeout will guard against cases where the browser never actually fires any events. I've set the default timeout to 10 seconds here; in the real world you might want to reduce that.
Now we'll generate 10 randomly-sized placekittens to use as images in the example.
var imgs=[];
for (var i = 0; i < 10; i++) imgs.push('<img src="http://placekitten.com/' + rnd() + '/' + rnd() + '"> ');
$('#imgs').html(imgs.join());
Finally, we'll put everything together with some magic:
$.when.apply($, $('#imgs img').loaded({timeout:10000}) ).done(function() {
alert('loaded successfully');
}).fail(function() {
alert('load failed or timed out');
});
$.when creates a master Deferred that gets resolved only when all of its child Deferreds resolve, or rejects when a child rejects. It normally expects you to pass each Deferred as an argument (it does not support passing in an array of Deferreds), so we have to apply our array. (I might do $.whenall = function(dfds) { $.when.apply($,dfds); }; so that your app code has a cleaner $.whenall( $('#imgs img').loaded() )...)
Try this:
$("#preload_div").html(
'<img src="image.png" alt="preload" class="preload" width="0" height="0">'
);
The event handler can be bound to the image:
$('preload').load(function () {
var html = "<p>Some text <img src='image.jpg' /></p><p>Some more text <img src='image2.jpg' /></p>";
$("div.output").html(html);
});
Of course, you would have to incorporate an .each() for each image to loop through all images.
EDIT: On one of my AJAX websites, I preload the next image I need, so when a user clicks the 'next' button, the image that the new content needs is already cached. See http://funl.es/p/1
One method I'm thinking of doing is running through the HTML with regular expressions or jQuery, finding all image URLs, loop through them and preload each with the image object. When all have been preloaded, then inject the HTML into the output div.
var imagesLoaded = [];
var imagesErrored = [];
$('img').each(function() {
$(this).load(function() {
imagesLoaded.push($(this).attr("src"));
if( (imagesLoaded.length + imagesErrored.length) == $('img').length ) {
displayResults(imagesLoaded, imagesErrored);
}
});
$(this).error(function() {
imagesErrored.push($(this).attr("src"));
if( (imagesLoaded.length + imagesErrored.length) == $('img').length ) {
displayResults(imagesLoaded, imagesErrored);
}
});
function displayResults(imagesLoaded, imagesErrored) {
for(var i = 0; i < imagesLoaded.length; i++) {
alert(imagesLoaded[i] + " has loaded successfully.");
$('#myDiv').append("<img src='" + imagesLoaded[i] + "' />");
}
for(var i = 0; i < imagesErrored.length; i++) {
alert(imagesLoaded[i] + " did NOT load successfully.");
}
}
The above loops through all images and checks whether or not they loaded, using the load event. Using the error event, we also get a collection of all images that for whatever reason did not load correctly. After all images have been preloaded, we can then inject them onto the page in the "displayResults" function. This is based loosely on the last paragraph in your question.
However, it doesn't use regular expressions, as they are not the right tool for manipulating the DOM. Fortunately, JavaScript and jQuery provide us with the tools we need to perform DOM manipulations and parsing activities.
Finally, from your question, it sounded like you may have been interested in knowing what images loaded successfully. The above collections that are built from the load and error events will provide you with those details, should you need them.
I think you should bind the load handler after you insert the images into the html.
DEMO
//Add image
$('#result').append('<img src= "<Your_Image_URL>" width="300" height="300"/>');
//Bind handler also add condition to not bind images that was not added before.
$('#result').find('img').not('.loaded').on('load', function () {
alert('Image Loaded');
//Add code that you want to do after the image is added
}).addClass('loaded');
Also please be aware of Caveats of the load event when used with images
A common challenge developers attempt to solve using the .load()
shortcut is to execute a function when an image (or collection of
images) have completely loaded. There are several known caveats with
this that should be noted. These are:
It doesn't work consistently nor reliably cross-browser
It doesn't fire correctly in WebKit if the image src is set to the same src as before
It doesn't correctly bubble up the DOM tree
Can cease to fire for images that already live in the browser's cache
Reference: http://api.jquery.com/load-event/
Have you considered using the jQuery 'on' event mechanism? Using 'on' should allow you to automatically bind 'load' handlers to each image as it gets dynamically added to the container and DOM.
Link: jQuery docs for'on' function
If you're using pre 1.7 jQuery, you'll need to use the 'live' function since 'on' was added with the 1.7 release.
Link: jQuery docs for 'live' function (deprecated)
I think that there is no easy way to do that. The thing that you could do is to load all the images on a div that is hidden ( display: none ).
When you want to show the pictures you can do:
$("#myDiv").show();

Using jquery append() in <head> (in a function/class)

I want to use the append() function from inside the <head>, in a function to be specific, like so:
function custom_img(src_img)
{
$("div").append("<img src='"+src_img+"'>");
}
var myimg = new custom_img("test.jpg");
This is a quick example that I just wrote out. I want my function to make a new image like that every time I create a new object like this. Obviously this doesn't work, since the append() requires to be in the body (I've tried this).
How would I do this?
The reason it's not working is because your div does not exist yet.
So you can either use the $(document).ready() function to wait for the document to load.
Or if you want the images to load together with the rest of the document, you could simply create a new div and insert the images there.
var div = $("div")
function custom_img(src) {
div.append($("img").attr("src", src));
}
Then when the document is fully loaded, you can go through the array and insert the loaded images in the DOM.
$(document).ready(function() {
$("#myDiv").append(div);
});
You can try using .after(), or even .html()
function custom_img(src_img)
{
$("div").after("<img src='"+src_img+"'>");
}
var myimg = new custom_img("test.jpg");
or
function custom_img(src_img)
{
$("div").html("<img src='"+src_img+"'>");
}
var myimg = new custom_img("test.jpg");

Categories