Loading images with ajax (in rails) [duplicate] - ajax

I want to load external images on my page asynchronously using jQuery and I have tried the following:
$.ajax({
url: "http://somedomain.com/image.jpg",
timeout:5000,
success: function() {
},
error: function(r,x) {
}
});
But it always returns error, is it even possible to load image like this?
I tried to use .load method and it works but I have no idea how I can set timeout if the image is not available (404). How can I do this?

No need for ajax. You can create a new image element, set its source attribute and place it somewhere in the document once it has finished loading:
var img = $("<img />").attr('src', 'http://somedomain.com/image.jpg')
.on('load', function() {
if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth == 0) {
alert('broken image!');
} else {
$("#something").append(img);
}
});

IF YOU REALLY NEED TO USE AJAX...
I came accross usecases where the onload handlers were not the right choice. In my case when printing via javascript. So there are actually two options to use AJAX style for this:
Solution 1
Use Base64 image data and a REST image service. If you have your own webservice, you can add a JSP/PHP REST script that offers images in Base64 encoding. Now how is that useful? I came across a cool new syntax for image encoding:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhE..."/>
So you can load the Image Base64 data using Ajax and then on completion you build the Base64 data string to the image! Great fun :). I recommend to use this site http://www.freeformatter.com/base64-encoder.html for image encoding.
$.ajax({
url : 'BASE64_IMAGE_REST_URL',
processData : false,
}).always(function(b64data){
$("#IMAGE_ID").attr("src", "data:image/png;base64,"+b64data);
});
Solution2:
Trick the browser to use its cache. This gives you a nice fadeIn() when the resource is in the browsers cache:
var url = 'IMAGE_URL';
$.ajax({
url : url,
cache: true,
processData : false,
}).always(function(){
$("#IMAGE_ID").attr("src", url).fadeIn();
});
However, both methods have its drawbacks: The first one only works on modern browsers. The second one has performance glitches and relies on assumption how the cache will be used.
cheers,
will

Using jQuery you may simply change the "src" attribute to "data-src". The image won't be loaded. But the location is stored with the tag. Which I like.
<img class="loadlater" data-src="path/to/image.ext"/>
A Simple piece of jQuery copies data-src to src, which will start loading the image when you need it. In my case when the page has finished loading.
$(document).ready(function(){
$(".loadlater").each(function(index, element){
$(element).attr("src", $(element).attr("data-src"));
});
});
I bet the jQuery code could be abbreviated, but it is understandable this way.

$(<img />).attr('src','http://somedomain.com/image.jpg');
Should be better than ajax because if its a gallery and you are looping through a list of pics, if the image is already in cache, it wont send another request to server. It will request in the case of jQuery/ajax and return a HTTP 304 (Not modified) and then use original image from cache if its already there. The above method reduces an empty request to server after the first loop of images in the gallery.

You can use a Deferred objects for ASYNC loading.
function load_img_async(source) {
return $.Deferred (function (task) {
var image = new Image();
image.onload = function () {task.resolve(image);}
image.onerror = function () {task.reject();}
image.src=source;
}).promise();
}
$.when(load_img_async(IMAGE_URL)).done(function (image) {
$(#id).empty().append(image);
});
Please pay attention: image.onload must be before image.src to prevent problems with cache.

If you just want to set the source of the image you can use this.
$("img").attr('src','http://somedomain.com/image.jpg');

This works too ..
var image = new Image();
image.src = 'image url';
image.onload = function(e){
// functionalities on load
}
$("#img-container").append(image);

AFAIK you would have to do a .load() function here as apposed to the .ajax(), but you could use jQuery setTimeout to keep it live (ish)
<script>
$(document).ready(function() {
$.ajaxSetup({
cache: false
});
$("#placeholder").load("PATH TO IMAGE");
var refreshId = setInterval(function() {
$("#placeholder").load("PATH TO IMAGE");
}, 500);
});
</script>

use .load to load your image. to test if you get an error ( let's say 404 ) you can do the following:
$("#img_id").error(function(){
//$(this).hide();
//alert("img not loaded");
//some action you whant here
});
careful - .error() event will not trigger when the src attribute is empty for an image.

//Puedes optar por esta solución:
var img = document.createElement('img');
img.setAttribute('src', element.source)
img.addEventListener('load', function(){
if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth == 0) {
alert('broken image!');
} else {
$("#imagenesHub").append(img);
}
});

$(function () {
if ($('#hdnFromGLMS')[0].value == 'MB9262') {
$('.clr').append('<img src="~/Images/CDAB_london.jpg">');
}
else
{
$('.clr').css("display", "none");
$('#imgIreland').css("display", "block");
$('.clrIrland').append('<img src="~/Images/Ireland-v1.jpg">');
}
});

Related

Remove previews from dropzone after success

I want to rollback the original dropzone with its message "drop files here" after the success event of dropzone or after the complete event of dropzone.
I don't want to see the preview after success or complete.
This is my dropzone script:
Dropzone.options.myAwesomeDropzone = {
paramName: "file", // The name that will be used to transfer the file
maxFilesize: 2, // MB
parallelUploads: 1,
success: function(file, response) {
var imageSrc = response;
$(".img-responsive").attr('src', imageSrc);
if (imageSrc == '/assets/images/offerfeatimg.jpg') {
$(".removebutton").hide();
} else {
$(".removebutton").show();
}
}
};
Leveraging #kkthxby3 's idea, the innerHTML for the thumbnail can be cleared in the success method using the following code:
success: function (file, response) {
file.previewElement.innerHTML = "";
}
The beauty of this approach is that it clears the thumbnail without firing the removedFile event.
This leaves the following html in the dom where the thumbnail was:
<div class="dz-preview dz-processing dz-image-preview dz-complete"></div>
but as you can see, the div above which is responsible for displaying the thumbnail is now empty.
Another approach is to remove even the enclosing div that wraps the thumbnail along with it's contents. This approach can be accomplished with the following code in the success method and leaves no trace of the thumbnail in the dom:
success: function (file, response) {
file.previewElement.parentNode.removeChild(file.previewElement);
}
Enjoy.
only need call method removeFile in success function
success: function (file, response) {
this.removeFile(file);
}
check doc dropzone
For me the easiest way to make the file preview not appear is with css.
dz-preview and dz-file-preview are a couple classes in the outer div of the preview html generated by the default template.
.dz-preview, .dz-file-preview {
display: none;
}
I also told it to not create thumbnails in the Dropzone.options.
Dropzone.options.myDropzone = {
paramName: "file",
maxFilesize: 2, // MB
url: 'post_image',
createImageThumbnails: false, // NO THUMBS!
init: function () {
this.on('sending', dz_sending),
this.on('success', dz_success),
this.on('error', dz_error),
this.on('complete', dz_complete) // Once it's done...
}
The template still generates all the preview html though. So in my 'complete' function dz_complete I delete it all.
function dz_complete(file) {
$('.dz-preview').remove(); // ...delete the template gen'd html.
}
Just an fyi...
The method 'removeAllFiles' is not necessarily the prime choice. Which is the same as 'removeFile(file)'.
I have an event handler for dropZone's 'removedfile' event... I'm using it to send a server message to delete the respective file from the server (should a user delete the thumbnail after it's been uploaded). Using the method 'removeAllFiles' (as well as the individualized 'removeFile(file)') fires the event 'removedfile' which deletes the uploaded images in addition to clearing the thumbnails.
So one could add some finessing around this but in the reality of it the method is not correct.
Looking through the api for Dropzone I am not seeing an API call to simply reset or clear the thumbnails... The method 'disable()' will clear the stored file names and what not but does not clear the thumbnails... Seems dropzoneJS is actually missing a critical API call to be honest.
My work around is to manually reset the containing div for dropzone:
document.getElementById("divNameWhereDropzoneClassIs").innerHTML = ""
This clears the thumbnails without firing off the event 'removedfile' which is supposed to be used for deleting an image from the server...
The easiest thing is to call the dropzone removeFile() method, using an event listener for the success event.
Dropzone.options.myAwesomeDropzone = {
paramName: "file",
maxFilesize: 2,
parallelUploads: 1,
init: function() {
this.on("success", function(file, response) {
var imageSrc = response;
$(".img-responsive").attr('src', imageSrc);
if(imageSrc == '/assets/images/offerfeatimg.jpg') {
$(".removebutton").hide();
} else {
$(".removebutton").show();
}
this.removeFile(file); // This line removes the preview
})
}
};
I was using file.previewElement.remove(), works fine in Chrome but does not work in IE.
Then I tried this.removeFile(file), but it didn't work for me.
After that i tried file.previewElement.innerHTML = "" which works in both Chrome and IE but it leaves an extra div where the preview elements were.
So this one works better for me...
success: function (file, response) {
file.previewElement.outerHTML = "";
}
If you want to remove an added file from the dropzone, you can call .removeFile(file). This method also triggers the removedfile event.
Here’s an example that would automatically remove a file when it’s finished uploading:
myDropzone.on("complete", function(file) {
myDropzone.removeFile(file);
});
If you want to remove all files, simply use .removeAllFiles(). Files that are in the process of being uploaded won’t be removed. If you want files that are currently uploading to be canceled, call .removeAllFiles(true) which will cancel the uploads.
100% Tested and Working:
$('#preview_image_container .dz-preview .dz-remove').attr('id','removeFile');
document.getElementById("removeFile").click();

Chrome: Prevent image reload when rebuilding image elements

Using AngularJS:
I'm displaying a list of images with ng-repeat. When I reset and rebuild the model (get new data from backend), I'm displaying the same images as before.
I understand these are new elements created by ng-repeat, but the image srcs are the same. Unlike IE or firefox, Chrome tries and gets a 403 for those same images and then renders them.
That causes a flicker. On IE and Firefox the images come from cache. No hit on the server to check for image changes. No flicker.
How can I prevent that? Should the images be served with some cache header? I tried loading the images to a dataurl, but then I hit the CORS problem, and would have to proxy those images on the backend to get them.
Possibly related: Chrome sometimes reloads image after jQuery .appendTo, recieves 304
Thanks
Some fix would be related to preload the images in javascript and after that display them
function loadImages(arrayOfImgs) {
var imageNumber=0;
$(arrayOfImgs).each(function(){
(new Image()).src = this;
if(arrayOfImgs.length == imageNumber) $scope.showImages = true;
else imageNumber++;
});
}
// Usage:
loadImages([
'img1.jpg',
'img2.jpg'
]);
if you are retriving images from backend use it at success promise
i hope it helps you
Check that example retrinving images from backend:
$scope.loading = true;
getImages().then(function (response) {
var objects= response.results;
var listImages = [];
angular.forEach(objects, function (item) {
listImages.push(item.UrlImage);
});
function preload(arrayOfImages) {
var numImages = 0;
$(arrayOfImages).each(function () {
var img = (new Image());
img.src = this;
$(img).load(function () {
numImages++;
if (numImages == arrayOfImages.length){
$scope.loading = false;
}
});
});
}
preload(listImages);
});

Ajax URL # isn't updating

I have a little problem with my script here. For some reason, it doesn't enable the #-tags and I don't know why. I created this javascript using the help of this tutorial. (The loading of the pages works well with no problems at all.)
Could someone please look it over and tell me why it doesn't work?
var default_content="";
$(document).ready(function(){ //executed after the page has loaded
checkURL(); //check if the URL has a reference to a page and load it
$('ul li a').click(function (e){ //traverse through all our navigation links..
checkURL(this.hash); //.. and assign them a new onclick event, using their own hash as a parameter (#page1 for example)
});
setInterval("checkURL()",250); //check for a change in the URL every 250 ms to detect if the history buttons have been used
});
var lasturl=""; //here we store the current URL hash
function checkURL(hash)
{
if(!hash) hash=window.location.hash; //if no parameter is provided, use the hash value from the current address
if(hash != lasturl) // if the hash value has changed
{
lasturl=hash; //update the current hash
loadPage(hash); // and load the new page
}
}
function loadPage(url) //the function that loads pages via AJAX
{
// Instead of stripping off #page, only
// strip off the # to use the rest of the URL
url=url.replace('#','');
$('#loading').css('visibility','visible'); //show the rotating gif animation
$.ajax({
type: "POST",
url: "load_page.php",
data: 'page='+url,
dataType: "html",
success: function(msg){
if(parseInt(msg)!=0) //if no errors
{
$('#content').html(msg); //load the returned html into pageContet
} $('#loading').css('visibility','hidden');//and hide the rotating gif
}
});
}
You can simplify this immensely by adding a function to listen to the hashchange event, like this:
$(window).on("hashchange", function() {
loadPage(window.location.hash);
});
This way you don't need to deal with timers or overriding click events on anchors.
You also don't need to keep track of lasthash since the hashchange even will only fire when the hash changes.

jQuery Masonry and Ajax-fetching to Append Items Causing Image Overlap

Another image overlap issue here using Masonry and Ajax to append items in Wordpress. The first time more items are appended, the images overlap. However, when the page is reloaded, the images no longer overlap. I realize after doing some research this has to do with calculating the height of the images.
From the help page on the Masonry website, it is suggested to use the getimagesize function in order to specify the width and height of the images.
However, this is where I am stuck. Because of my limited knowledge of PHP, I have no idea how to utilize this function or where to place it in my code, so I'm looking for a little direction here. Can anyone help me figure out how to integrate the getimagesize function into my code?
Here is the masonry code:
$(document).ready(function(){
var $container = $('#loops_wrapper');
$container.imagesLoaded( function(){
$container.masonry({
itemSelector : '.post_box',
columnWidth: 302
});
});
});
This is the ajax fetching code:
$('.load_more_cont a').live('click', function(e) {
e.preventDefault();
$(this).addClass('loading').text('Loading...');
$.ajax({
type: "GET",
url: $(this).attr('href') + '#loops_wrapper',
dataType: "html",
success: function(out) {
result = $(out).find('.post_box');
nextlink = $(out).find('.load_more_cont a').attr('href');
$('#loops_wrapper').append(result).masonry('appended', result);
$('.load_more_cont a').removeClass('loading').text('Load more posts');
if (nextlink != undefined) {
$('.load_more_cont a').attr('href', nextlink);
} else {
$('.load_more_cont').remove();
}
}
});
});
You could try to implement David DeSandro's timer approach here for appending images...
"As recommended in the primer, the best solution to handle images is to have the size attributes defined in the img tag, especially when using Infinite Scroll. This is the solution employed in the example below.
Of course, this is not a viable option in some CMSs, most notably Tumblr. In this situation, Masonry needs to be called after the newly-appended images are fully loaded. This is done by delaying the Masonry callback."
function( newElements ) {
setTimeout(function() {
$wall.masonry({ appendedContent: $(newElements) });
}, 1000);
}
EDIT: If you can't implement the common delay idea for appending items with infinite scroll, you could try reloading after appending new items so instead of
$('#loops_wrapper').append(result).masonry('appended', result);
do it like that
$("#loops_wrapper").append(result).masonry('reload');

jquery .get download content fully before rendering

Is there a way to render content only after it's fully downloaded using AJAX/get/load with jQuery?
As it stands currently, the loader shows while the 'html' is being downloaded, but once that's done it starts rendering. There's lots of images in the html so they start loading independently after the render.
Is this good design practice? In my opinion once the loader disappears, everything should render 100%, but of course this will increase load time.
Can I achieve this without any 'hacks'?
$(document).ready(function() {
$('#clicks').click(function(){
$('#portfolio').append("<div id='loader'><img src='images/loader.gif'/></div>");
$.get("moreProjects.html", function(datas){
$('#portfolio').append(datas);
}, 'html').complete(function() {
$('#loader').hide();
});
return false;
});
});
You could always store the data returned in a variable and then append it in the complete function:
var returnedData;
$('#clicks').click(function(){
$('#portfolio').append("<div id='loader'><img src='images/loader.gif'/></div>");
$.get("moreProjects.html", function(datas){
returnedData = datas;
}, 'html').complete(function() {
$('#portfolio').append(returnedData);
$('#loader').hide();
});
return false;
});
Another option would be to use a hidden div container to load the content and then show on complete:
$('#clicks').click(function(){
$('#portfolio').append("<div id='loader'><img src='images/loader.gif'/></div>");
$('#portfolio').append("<div id='content' style='display:none'></div>");
$.get("moreProjects.html", function(datas){
$('#portfolio #content').append(datas);
}, 'html').complete(function() {
$('#portfolio #content').show();
$('#loader').hide();
});
return false;
});
Get the HTML, place it on your page or preload with JS, if placing it on your page the images can not be hidden if they are to be loaded, but they can be placed of screen.
When the images are loaded, move the HTML to your portfolio element.
The code below is just an example, not tested, and the load function will probably fire on the first image that is loaded, I think ?
If so you will have to count the images, place a load function on each image, and then show the HTML when all images have loaded, or you could try just attaching the load function to the last image in your HTML, but there is no guarantee that the last image in the markup is also the last to load, but it often is.
There could also be a problem with load if images are cached by the browser, if so you need to find another solution, or turn of caching in $.ajax!
$('#clicks').on('click', function(){
$('#portfolio').append("<div id='loader'><img src='images/loader.gif'/></div>");
var jqxhr = $.ajax({
type:'GET',
url: 'moreProjects.html',
datatype: 'html',
done: function(datas) {
$('<div id="somediv"></div>').append(datas)
.css({position: 'fixed', left: -5000})
.appendTo('body');
}
});
jqxhr.always(function() {
$('img', '#somediv').on('load', function() {
$('#loader').remove();
$('#portfolio').append($('#somediv').contents());
});
});
return false;
});
Check this link, the last post: Wait untill all images are loaded
In my opinion what you have to do is to save the html in a variable,
then filter out all the img tags and pass it to the _loadimages function
in the post i give you setting the complete callback.
Something like this:
var $retData = $(datas);
var $imgs = $retData.find('img');
_loadimages($imgs,function(){
$('#portfolio #content').append($retData);
});

Resources