Convert each image input to DataUrl or Base64 image while iterating - javascript

var toPush = []
for(var i = 1; i <= myVariable; i++){
var variable1 = document.getElementById('q' + i).value;
var var2 = document.getElementById(i + 'x').value;
var var3 = document.getElementById(i + 'y').value;
var var4 = document.getElementById(i + 'z').value;
var var5 = document.getElementById(i + 'd1').value;
var var6 = document.getElementById('xy' + i).value;
var file = document.getElementById("fileup" + i);
var twofour = [var2, var3, var4, var5];
let reader = new FileReader();
reader.readAsDataURL(file.files[0]);
reader.onload = function () {
pictureURL = reader.result;
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
toPush.push({"variable1": variable1, "twofour": twofour, "pictureURL": pictureURL}
}
The application can add X many inputs by appending them do div. When it comes to pushing the data, I want to have the file input, which is the only image input, be read as DataURL, so it can show be used as a source to an image preview. I don't know if it is because of the iteration, but the pictureURL variable pushes as empty: in the database I got "pictureURL": "".
Is there any way around it?
Thank you in advance.

There are multiple issues with this code. The reason that you're not receiving the pictureUrl is because you're reading it before it's ready.
FileReader reads the file asynchronously. It provides us a callback onload that is executed when it has read the file. We get the content of the file as reader.result only when this callback is executed. You have to rewrite your code to process the content of the file when it's either FileReader.onload or FileReader.onerror are executed.
See the working example below. I have removed unnecessary code. You can run the code by clicking on Run code snippet button at the bottom of the post
function showIcons() {
let files = document.querySelector('#files').files;
if(files.length) {
document.querySelector('#show-icons-error').textContent = "";
} else {
document.querySelector('#show-icons-error').textContent = 'No files have been selected';
}
let imageIcons = document.querySelector('#image-icons');
imageIcons.innerHTML = '';
let imageUrlArr = [];
for(var i = 0; i < files.length; i++) {
let imageIconHolder = document.createElement('img');
imageIconHolder.classList.add('image-icon');
imageIconHolder.setAttribute('image-index', i);
imageIcons.appendChild(imageIconHolder);
let file = files[i];
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
pictureURL = reader.result;
imageIconHolder.src = pictureURL;
imageUrlArr[i] = pictureURL;//Setting ith image, not pushing.
};
reader.onerror = function (error) {
console.log(`Error loading image at index : ${i}, error: ${error}`);
imageUrlArr[i] = error;//Error for ith image
};
}
}
.image-icon {
width: 10em;
display: block;
min-height: 5em;
}
<html>
<body>
<label for="files" class="btn">Select Images</label>
<input id="files" type="file" value="Select File" accept="image/*" multiple="multiple">
<br/>
<br/>
<div>
<button id="show-icons" onclick="showIcons()">Show Icons</button>
<span id='show-icons-error' style="color: red; font-weight: bold;"></span>
</div>
<br/>
<div id="image-icons">
</div>
</body>
</html>

Related

Multiple thumbnail images before upload with FileReader

I need help with making thumbnail images before uploading. I read a lot of questions here, but my problem (as I think) is a bit different.
So my code:
function nextImg(num, name){
var out = '<div class="row"><div class="col-md-2 col-xs-12" id="img_'+num+'"><img class="img-responsive pad img-thumbnail" id="imgreal_'+num+'" src="#" alt="'+name+'"></div></div>';
return out;
}
function showImgs(event){
var files = event.target.files;
if(files['length'] > 0){
var div_edit = ""
for(var i = 0; i < files['length']; i++){
div_edit += nextImg(i,files[i]['name']);
}
document.getElementById("img_container").innerHTML = div_edit;
for(var i = 0; i < files['length']; i++){
var reader = new FileReader();
console.log(i);
reader.onload = function (e) {
var num = "imgreal_"+i;
console.log(num);
var output = document.getElementById(num);
output.src = reader.result;
}
reader.readAsDataURL(event.target.files[i]);
}
}else{
document.getElementById('mainTAGs').style.display = "none";
}
}
<form role = "form" method = "post">
<div class="container col-md-12 col-xs-12" id="img_container">
</div>
</form>
So when I iterate over the opened images in the second for cycle the code gave all reader.onload function uniq "imgreal_#" id.
When onload was called I log the id and it is always the end criteria of the for cycle.
For example, let say I want to upload 3 images, then all the getElementById in the reader.onload function called with "imgreal_3" instead of "imgreal_0"... "imgreal_2".
Any suggestion how to solve it?
THX in advance! :)
This is the common gotcha for JS. To make it work you should store somewhere current iteration value for the async functions to access it later. E.g. you can store the index in IIFE:
(function() {
reader.onload = function (e) {
var num = "imgreal_"+i;
console.log(num);
var output = document.getElementById(num);
output.src = reader.result;
}
})(i)
The solution was:
(function(n) {
var reader = new FileReader();
reader.onload = function (e) {
var num = "imgreal_"+n;
console.log(num);
var output = document.getElementById(num);
output.src = reader.result;
}
reader.readAsDataURL(event.target.files[n]);
})(i);

Dynamically updating divs using for LOOP

I've been trying to use a for loop to dynamically update divs, but there seems to be a problem. The first time I run it runs fine and chrome logs...
gallery.js:9 class length = 1
gallery.js:11 testing uniqueId-> product_1
gallery.js:13 adding uniqueID product_1 to class
gallery.js:15 j is -->0
gallery.js:17 updated n.o of images in the class to 1
but the second time I run it something goes wrong...
gallery.js:9 class length = 2
gallery.js:11 testing uniqueId-> product_2
gallery.js:13 adding uniqueID product_2 to class
gallery.js:15 j is -->0
gallery.js:13 adding uniqueID product_2 to class
gallery.js:15 j is -->1
gallery.js:17 updated n.o of images in the class to 2
As you can see line 13-15 repeat and somehow, that names all the divs the same, e.g from product_0 to product_1...etc..
Heres the code:
var clss = document.getElementsByClassName('thumbnail');
var clssLength = clss.length;
console.log('class length = ' + clssLength);
var uniqueId = "product_" + clssLength;
console.log('testing uniqueId-> ' + uniqueId);
for (var j = 0; j < clss.length; j++) {
clss[j].setAttribute('id', uniqueId);
console.log('j is -->' + j);
}
Thanks in advance
As I was saying, I should've omitted the for loop (not necessary)...here's the actual code, I wanted to dynamically give upload previews unique IDs.
function updateImageId () {
var clss = document.getElementsByClassName('thumbnail');
var clssLength = clss.length;
var idFix = clssLength - 1;
console.log('class length = ' + clssLength);
var uniqueId = "product_" + clssLength;
console.log('testing uniqueId-> ' + uniqueId);
console.log('adding uniqueID '+uniqueId+' to class');
clss[idFix].setAttribute('id', uniqueId);
console.log('updated n.o of images in the class to ' + clssLength);
}
function previewImage(file) {
var galleryId = "gallery";
var gallery = document.getElementById(galleryId);
var imageType = /image.*/;
if (!file.type.match(imageType)) {
throw "File Type must be an image";
}
var thumb = document.createElement("div");
thumb.classList.add('thumbnail');
var img = document.createElement("img");
img.file = file;
thumb.appendChild(img);
gallery.appendChild(thumb);
// Using FileReader to display the image content
var reader = new FileReader()
reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
reader.readAsDataURL(file);
}
var uploadfiles = document.querySelector('#fileinput');
uploadfiles.addEventListener('change', function () {
var files = this.files;
for(var i=0; i<files.length; i++){
previewImage(this.files[i]);
setTimeout(updateImageId, 500);
}
}, false);
and html:
<head>
<meta charset="UTF-8">
<title>Preview images</title>
<style>
#gallery .thumbnail{
width:150px;
height: 150px;
float:left;
margin:2px;
}
#gallery .thumbnail img{
width:150px;
height
</style>
</head>
<body>
<h2>Upload images ...</h2>
<input type="file" id="fileinput" multiple="multiple" accept="image/*" />
<div id="gallery">
<!--div class = "thumbnail" id='product_1' will appear-->
</div>
</body>

How to load image from directory, then show onclick

I am trying to have a function which has functions that do the following.
One function to store the files i get with input into the parent functions loadedimages array(loadimages).
One function to show those files in the correct component(showLoadedImages).
And one function to make the correct img file appear on the correct component.
The last function is what i want it to be like(it does not work).
The other two seem ok.
The problem i have is how to make the last function work while using the loadedimages array. You can change what i store in the array , i wouldnt mind.
Here is the JS code:
function imgviewer() {
"use strict";
var loadedimages = [];
var lidivs = [];
function loadimages() {
var files = document.getElementById("images").files;
for (var i = 0; i < files.length; i++) {
var file = files[i];
if (!file.name.match(/\.(jpg|jpeg|png|gif)$/)) {
alert('THERE IS NO IMAGE IN THIS DIRECTORY.');
break;
}
loadedimages.push(file);
}
}
function showLoadedImages(elem) {
loadimages();
var ld = loadedimages;
//var files = getLoadedImages(); //filelist obj
for (var i = 0; i < ld.length; i++) {
var file = ld[i];
var reader = new FileReader();
reader.onload = (function(file) {
return function(e) {
// Render thumbnail.
var span = document.createElement(
'span');
span.innerHTML = [
'<img class="tile" src="',
e.target.result,
'" title="', encodeURI(
file.name), '">'
].join('');
document.getElementById(elem).insertBefore(
span, null);
lidivs.push(span);
};
})(file);
// Read in the image file as a data URL.
reader.readAsDataURL(file);
}
}
function showImage(index, elem) {
var chosenFile = loadedimages[index];
document.getElementById(elem).src = chosenFile;
}
document.getElementById('images').addEventListener('change', function(){
showLoadedImages("main");
}, false);
}
And some HTML
<form name="uploadForm">
<input id="images" type="file" webkitdirectory mozdirectory directory name="myFiles"
multiple/>
<span id="list"></span>
</form>
<div id="sidebar1"><img id="willchange" src="images/railaythailand.jpg" width="1200" height="832" alt=""/></div>
<div id="main"></div>
When i call showLoadedImages("main") the images are shown in main div. I want to be able to click those images so that they appear on "willchange" .
This does what you asked for. There are a number of other issues with your code that you might want to address, starting with the images are not thumbnails at all (and shrunken images take just as long to load as the original), but perhaps I'm missing something.
"use strict";
var loadedimages = [];
var lidivs = [];
function loadimages() {
var files = document.getElementById("images").files;
for (var i = 0; i < files.length; i++) {
var file = files[i];
if (!file.name.match(/\.(jpg|jpeg|png|gif)$/)) {
continue;
}
loadedimages.push(file);
}
loadedimages.length || alert('THERE IS NO IMAGE IN THIS DIRECTORY.');
}
function showLoadedImages(elem) {
loadimages();
var ld = loadedimages;
//var files = getLoadedImages(); //filelist obj
for (var i = 0; i < ld.length; i++) {
var file = ld[i];
var reader = new FileReader();
reader.onload = (function(file) {
return function(e) {
// Render thumbnail.
var span = document.createElement(
'span');
span.innerHTML = [
'<img data-index="',
lidivs.length,
'" class="tile" src="',
e.target.result,
'" title="', encodeURI(
file.name), '">'
].join('');
span.addEventListener("click", foo );
document.getElementById(elem).insertBefore(
span, null);
lidivs.push(span);
};
})(file);
// Read in the image file as a data URL.
reader.readAsDataURL(file);
}
}
function showImage(index, elem) {
document.getElementById(elem).src = lidivs[index].children[0].src;
}
function foo(event) {
showImage(event.target.dataset.index, "willchange");
}
function show() {
showLoadedImages("list");
}
function init() {
document.getElementById("images").addEventListener("change", show, false);
}
document.addEventListener( "DOMContentLoaded", init, false );
<body>
<form name="uploadForm">
<input id="images" type="file" webkitdirectory mozdirectory directory name="myFiles"
multiple/>
<span id="list"></span>
</form>
<div id="sidebar1"><img id="willchange" src="images/railaythailand.jpg" width="1200" height="832" alt=""/></div>
</body>

javascript for-loop repeating last iteration

I am trying to crop-resize n display an image on client-browser using JS. I am able to do so except that my text loop is wrong. You can see in the image below that it is repeating the last iteration. My image loop works fine though. Hint - First filename text is supposed to be black.jpg.
Am unable to solve the issue after having tried for several hours. Given below is a trimmed version of the code. If needed here is the complete version of the script. Please help, I am still learning.
HTML
<input type="file" id="input" onchange="prevCrop()" multiple>
<ul id="listWrapper"></ul>
JAVASCRIPT
function prevCrop() {
var files = document.querySelector('input[type=file]').files;
for (var i = 0; i < files.length; i++) {
var file = files[i];
var fileSize = Math.floor(file.size/1024);
var info = file.name + " " + fileSize + " KB : iteration number - " + i;
var reader = new FileReader();
if (reader != null) {
reader.onload = GetThumbnail;
reader.readAsDataURL(file);
}
}
function GetThumbnail(e) {
var canvas = document.createElement("canvas");
var newImage = new Image();
newImage.src = e.target.result;
newImage.onload = cropResize;
function cropResize() {
canvas.width = 70;
canvas.height = 70;
### more codes here that handles image ###
var dataURL = canvas.toDataURL("image/jpg");
var thumbList = document.createElement('div');
thumbList.setAttribute('class', 'tlistClass');
var nImg = document.createElement('img');
nImg.src = dataURL;
var infoSpan = document.createElement('span');
infoSpan.innerHTML = info;
var handle = document.getElementById("listWrapper").appendChild(thumbList);
handle.appendChild(nImg);
handle.appendChild(infoSpan);
}
}
}
This happens because the onload callback function is triggered asynchronously, so after your code has already ended. At that time info has the string that was assigned to it in the last iteration. Only then the onload events are fired, resulting in the different calls of GetThumbnail, which all will see the same value for info.
Instead bind the value of info to the callback function like this:
reader.onload = GetThumbnail.bind(null, info);
...and define the corresponding parameter for it in the GetThumbnail function:
function GetThumbnail(info, e) {
That way every call of that function will posses of the proper value for info.

Get full path image into input file

I want get the full path image from input file for show image preview and use for example attr of jquery for insert this into scr to this temporal image path , for example i think in that
var filePath = $(this).val();
console.log(filePath);
jQuery('#preview').attr("src",""+img_p);
The problem i don´t know how i can get this temporal path from input file for show and insert this path for the preview image until send to upload in the system
Thank´s , Regards
MOZILLA DEVELOPER NETWORK show us an example to do that:
<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
Select some files
<div id="fileList">
<p>No files selected!</p>
</div>
<script>
window.URL = window.URL || window.webkitURL;
var fileSelect = document.getElementById("fileSelect"),
fileElem = document.getElementById("fileElem"),
fileList = document.getElementById("fileList");
fileSelect.addEventListener("click", function (e) {
if (fileElem) {
fileElem.click();
}
e.preventDefault(); // prevent navigation to "#"
}, false);
function handleFiles(files) {
if (!files.length) {
fileList.innerHTML = "<p>No files selected!</p>";
} else {
var list = document.createElement("ul");
for (var i = 0; i < files.length; i++) {
var li = document.createElement("li");
list.appendChild(li);
var img = document.createElement("img");
img.src = window.URL.createObjectURL(files[i]);
img.height = 60;
img.onload = function(e) {
window.URL.revokeObjectURL(this.src);
}
li.appendChild(img);
var info = document.createElement("span");
info.innerHTML = files[i].name + ": " + files[i].size + " bytes";
li.appendChild(info);
}
fileList.appendChild(list);
}
}
</script>
HERE the Mozilla DOC.
HERE some problem to do that.

Categories

Resources