Previewing Images in Order with JQuery - javascript

I'm trying to build a form in which it is possible to select images and then immediately preview all images, and flag certain images before the upload. The images are flagged using a checkbox which contain as value the name of the file, and the checkboxes are displayed on top of the images.
The images are visible, however the order in which they appear seems to be random and because of this the wrong checkbox is displayed over most of the images. Is there any way to control the order in which the images appear, or to put the correct checkbox with the correct image? This is the jQuery code that I am currently using.
$(function() {
// Multiple images preview in browser
var imagesPreview = function(input, placeToInsertImagePreview) {
if (input.files) {
var filesAmount = input.files.length;
counter=0;
for (i = 0; i < filesAmount; i++) {
var reader = new FileReader();
reader.onload = function(event) {
$($.parseHTML('<div class="imagewrapper" style="position:relative">'))
.append($($.parseHTML('<img class="parent-width">')).attr('src', event.target.result))
.append($($.parseHTML("<input class='imgcheckbox' name='featured[]' value='"+input.files[counter].name+"' type='checkbox'>")))
.appendTo(placeToInsertImagePreview);
counter++;
}
reader.readAsDataURL(input.files[i]);
}
}
};
$('#photoinput').on('change', function() {
imagesPreview(this, '.photoaddview');
});
});

In this fiddle: https://jsfiddle.net/4ad6zLfq/ : what I've done is used a LET variable, which is block scoped so your iteration variable won't ever get desynced from the image you're loading, and I've made your file loading 'reader' thing into a promise
function loadFile(file) {
return new Promise(function(resolve, reject) {
var reader = new FileReader();
reader.onload = function() {
resolve(event.target.result);
};
reader.readAsDataURL(file);
})
}
var imagesPreview = function(input, placeToInsertImagePreview) {
if (input.files) {
var filesAmount = input.files.length;
for (let i = 0; i < filesAmount; i++) {
loadFile(input.files[i])
.then(function(data) {
$($.parseHTML('<div class="imagewrapper" style="position:relative">'))
.append($($.parseHTML('<img class="parent-width">')).attr('src', data))
.append($($.parseHTML("<input class='imgcheckbox' name='featured[]' value='"+input.files[i].name+"' type='checkbox'>")))
.appendTo(placeToInsertImagePreview);
})
}
}
};
[edit]
for the record, this does NOT force the images to load in the correct order. It does, however, force the checkboxes next to the correct images, which was as you noticed a fault with the way it originally was. It's actually fairly easy to use async/await to take the example I created and ALSO make it load in order.

Related

How to display paragraphs and images from div in order?

I am building a small web-tool where editors can write content by using buttons to add paragraphs and images. I store the elements with an id ((number of element) starting at 0 and incremented for every new element) and load with a button in order to a div "preview" where the content is supposed to be displayed as in the web page later on.
My issue is that, for a reason I don't understand, the image is always displayed below all the paragraphs instead of being in order. Presumably there is an easy fix, but I am very new to HTML, CSS and JS and couldn't find the solution online.
Sorry if this is a stupid mistake or the solution was already posted somewhere.
Javascript handling the preview rendering:
// Preview current document status
document.getElementById("previewButton").addEventListener("click", function() {
// Clear
document.getElementById("preview").innerHTML = "";
// Add all elements properly
var section = document.getElementById("preview");
var id = "preview";
for (var counter = 0; counter < element_counter; counter++) {
var type = document.getElementById(counter).nodeName;
// If text element
if (type === "TEXTAREA") {
var paragraph = document.createElement("p");
var text = document.getElementById(counter).value;
paragraph.setAttribute("id", id + counter);
paragraph.setAttribute("class", "flow-text");
paragraph.append(text);
section.appendChild(paragraph);
}
// If image element
if (type === "INPUT") {
var file = document.getElementById(counter).files[0];
var reader = new FileReader();
reader.onload = function(e) {
var image = document.createElement("img");
image.setAttribute("id", id + counter);
image.setAttribute("src", e.target.result);
image.setAttribute("class", "materialboxed responsive-img");
section.appendChild(image);
}
reader.readAsDataURL(file);
}
}
});
This might work. I can't test though without your code. However basically the principle at work is to isolate some of the vars so they represent distinct instantiations. And then immediately add the image element to the DOM. The reader.onload is expected to run asynchronously still.
enter code here if (type === "INPUT") {
(function() {
var file = document.getElementById(counter).files[0];
var reader = new FileReader();
var image = document.createElement("img");
image.setAttribute("id", id + counter);
image.setAttribute("class", "materialboxed responsive-img");
section.appendChild(image);
reader.onload = function(e) {
image.setAttribute("src", e.target.result);
}
reader.readAsDataURL(file);
}());
}

javascript FileReader multiple not working

I'm using one input in html to select and upload image one by one or multiple.
I want to show preview before upload image and I'm using js FileReader. It's working for one image but not working for multiple images.
$('#fileToUpload').change(function(){
var file = this.files;
filepreview(file);
});
function filepreview(files)
{
var length = files.length;
for(var i=0 ; i<length ; i++)
{
var file = files[i];
var reader = new FileReader();
reader.addEventListener("load",function(e){
$('#pic'+i+'').attr('src' , ''+e.target.result+'');
});
reader.readAsDataURL(file);
}
}
Its basically that i is always length, as the events occur after the loop iterated:
reader.addEventListener("load",function(e){//async stuff
$('#pic'+i+'').attr('src' , ''+e.target.result+'');//i = length
});
So you may want to bind i:
reader.addEventListener("load",function(i,e){//take over the bound i
$('#pic'+i+'').attr('src' , ''+e.target.result+'');
}.bind(this,i));//the magic part

how to get photo compleet url form form in array

I am trying to use jquery to take a picture from my comp via a form.
- So I want the entire URL out of the form in an array
It works + / - in Dreamweaver, but not in the explorer browsers not even chrome
The end goal is a calendar with picture / app for people with disabilities, but as long as I get to go through the phone gap
var foto= new Array();
var i=-1;
//foto=["toets.png"];
$('#fotouit').append("FOTO UIT");
$('#knop01').click(function(){
$('input:file[name=foto]').each(function(){
//alert($(this).val());
foto.push($(this).val());
foto.forEach( function(){
i++;
$('#fotouit').append(foto[i]);
$('#fotouit').append('<img src=" '+ foto[i] + ' " width="100" height="100" />');
});
});
})
I don't think it is possible to get the URL of the picture in you computer's local filesystem, but you can use Javascript's FileReader API to read the contents of the uploaded file (in your case, the picture). The read contents can be used in the src of the img element as you did in your example code.
This is an in depth explanation of what you're trying to accomplish: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications
Example:
function handleFiles(files) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
var imageType = /image.*/;
if (!file.type.match(imageType)) {
continue;
}
var img = document.createElement("img");
img.classList.add("obj");
img.file = file;
preview.appendChild(img); // Assuming that "preview" is a the div output where the content will be displayed.
var reader = new FileReader();
reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
reader.readAsDataURL(file);
}
}
Note:
You can use the multiple attribute on a file input to allow selecting many files with one input
You can use the file inputs change event to immediately capture the files rather than providing a second button to click

How to set error image for all images on page?

I would like to show my own error image when an image cant load successfully.
I thought of a JavaScript function:
<script type="text/javascript">
var images = document.getElementsByTagName("img");
for (var i = 0; i < images.length; i++) {
images[i].onerror = onErrorImage(images[i]);
}
function onErrorImage(element){
element.onerror = null;
element.src = 'errorImage.png';
}
</script>
But this doesn't work. This turns every image on the page into my own error image.
Is there another simple way to show my own error image on error?
Or is there another way to bind a function to an event like i did on line 4? Because I'm pretty sure the script fails on that line.
Solution may be in jQuery.
It should be i guess:
images[i].onerror = function(){onErrorImage(this);}
There are a lot of ways to do this, I will show you one of them :
You can make all of your images with "fake-src" and load them when the document is ready. Of course you can make a loader till they are downloading.
Here is a function I write for you:
imagesReady = function () {
var myImgs = document.getElementsByTagName("img");
for (var i = 0; i < myImgs.length; i++) {
getImageReady(myImgs[i]);
};
function getImageReady(el) {
var url = el.getAttribute("src-fake");
var image = document.createElement("img");
image.onload = function() {
el.src = url;
el.style.opacity = 1;
//this image is ok, that why we put his src to be the fake src
};
image.onerror = function (err) {
console.log("err on load :"+image.src);
el.src = url;
//this image fail!
}
image.src = url;
}
}
imagesReady();

Can I "pre-load" an image with JS to be used as a CSS background-image?

Can images be preemptively loaded into the page with javascript so that they can be used at any time as a CSS background image without any request/upload delay?
If so, how?
You don't even need to use JS for this (with the downside of delaying the page load event). Include something like this:
<img src="/path/to/image.jpg.png.gif.bmp" style="display: none" />
This will trigger a request for the image, and add it to the local cache. When you set the CSS background-image property, the image will already be in the local cache, eliminating the delay of another request.
Alternatively, you can accomplish the same thing without delaying the page load by creating the images in JavaScript (this solution allows for multiple images):
function preload(list, callback, imageCallback) {
var at, len;
at = len = list.length;
for (var i = 0; i < len; i++ ) {
var img = new Image();
img.onload = function() {
if( imageCallback ) {
imageCallback.call(this, this, len-at, len);
}
if( !--at ) {
callback(list);
}
};
img.src = list[i];
list[i] = img;
}
}
You'd call this with:
var list = preload(["1.png","2.png","3.png" ... ], function complete(list) {
console.log('images all loaded!');
}, function loaded(image, index, listCount) {
console.log('image ' + index + ' of + 'listCount + 'is loaded');
});
(Thanks to #rlemon for the preload code)
I don't think that using an hidden img tag is the correct way, i'd rather use an "new Img(url)" and attaching to it an onload event where you can set the image as background-image to the element you want.
img = new Image();
img.onload = function(){
// set background-image
};
img.src = image_url;
be sure to put img.src after attaching onload, or you risk that the image is loaded before the event is attached.
Maybe a more complete base to build on:
function preload(list, callback, imageCallback, errorCallback) {
if (typeof(list) === "undefined"
|| list.length === 0) {
return;
}
var len = list.length;
var timers = {};
var checkLen0 = function() {
if (len === 0) {
if (typeof(callback) === "function") {
callback();
}
delete(timers)
}
}
var onload = function() {
clearTimeout(timers[img]);
if (typeof(imageCallback) === "function") {
imageCallback.call(img);
}
len--;
checkLen0();
}
var onerror = function() {
clearTimeout(timers[img]);
if (typeof(errorCallback) === "function") {
errorCallback.call(img);
}
len--;
checkLen0();
}
for (var i = 0; i < list.length; i++ ) {
var img = new Image();
img.onload = onload;
timers[img] = window.setTimeout(5000, onerror);
img.src = list[i];
}
}
While SomeKittens answer is valid, it'll delay the page load as commented by Jimmy. If you are using jquery, I'd go with something like this instead to keep your style, structure and logic separated:
<style>
.preload-img { display: none; }
</style>
...
<div class = "preload-img">/path/to/image.jpg.png.gif.bmp</div>
...
<script>
$(document).ready(function(){
$(".preload-img").each(function(){
preloadImage = new Image();
preloadImage.src = $(this).html();
});
});
</script>
Of course, from there on you can optimize/change it. The advantadge of this is that you can create the <div> dynamically with PHP and you can have all your javascript cached properly as a separated file.
There is an excellent framework for this job called Emerge.js
http://ilyabirman.net/projects/emerge/
Quote from project page:
Emerge.js is a framework for coordinated page loading. Normally, when a complex web page is loading, images appear in random order, causing unpleasant flashing. To replace it with nice and coordinated animations, programming is required. Emerge.js simplifies the task by removing the need to write any Javascript code. The framework uses a declarative approach, where you specify a desired behavior for each element and do not think about the implementation. Emerge.js uses jQuery.
Just as a caveat to SomeKittens' answer above, a particularly large background image should probably be added as a hidden background / via JavaScript after page load, as content images delay the firing of window.onload and may therefore create the perception of a slow loading page.
Given that it sounds like you're using dynamic content anyway, this may be an acceptable solution. It also allows you to do preloading programmatically as required, which may be better for maintenance.

Categories

Resources