readAsDataURL is not a blob, yet the images show - javascript

I have a file input which then preview the images after adding. The images show, but I get:
Uncaught TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'."
What's causing this, surely they wouldn't show still?
$('#image-upload-input').on('change', function() {
var files = document.getElementById('image-upload-input').files;
for (var key in files) {
if (files[key]) {
var reader = new FileReader();
reader.onload = function(e) {
$('.image-upload-container').append('<img src="'+ e.target.result +'" style="width: 100px;">');
}
reader.readAsDataURL(files[key]);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="image-upload-input" type="file" multiple>
<div class="image-upload-container"></div>

You are misusing the for( in ) loop. As it iterates it chokes on the length property - which is not a Blob Object. This happens because the for( in ) iterates over all (enumerable) object properties and not just "own properties". Reference
You have two choices:
Stick to the traditional (and always works) for() loop
Use the for( of ) loop
The for( of ) loop will only iterate "own properties" while the traditional for() loop will always, always work when a length property is available.
$('#image-upload-input').on('change', function() {
var files = document.getElementById('image-upload-input').files;
for(file of files) {
if (file) {
var reader = new FileReader();
reader.onload = function(e) {
$('.image-upload-container').append('<img src="'+ e.target.result +'" style="width: 100px;">');
}
reader.readAsDataURL(file);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="image-upload-input" type="file" multiple>
<div class="image-upload-container"></div>

Good example of few issues together.
Exception you get - is because files isn't real array, so for ... in - iterates over "0", "1"... "item","length" keys.
You can't use async function inside loop without isolating the scope
My personal opinion: don't use jQuery if you can :-)
$('#image-upload-input').on('change', function() {
var files = document.getElementById('image-upload-input').files;
for (var key=0; key < files.length; key++) {
(function(){
var reader = new FileReader();
var file = files[key];
reader.onload = function(e) {
var img = document.createElement('img');
img.style= "width:100px";
img.src = reader.result;
$('.image-upload-container').append($(img));
}
reader. readAsDataURL(file);
})();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="image-upload-input" type="file" multiple>
<div class="image-upload-container"></div>

I would have ditched the FileReader for URL.createObjectURL and just use a regular for loop
$('#image-upload-input').on('change', function() {
var files = document.getElementById('image-upload-input').files;
for (var i = 0; i < files.length; i++) {
var url = URL.createObjectURL(files[i]);
$('.image-upload-container').append('<img src='+ url +' style="width: 100px;">');
}
});
and possible added this extra attribute to the input
accept="image/*"

Related

I can't print the list on the screen

I want to list my json data as checkboxlist. I wrote this code. I'm printing this way. I don't know where I'm doing wrong. I get my jSON data from excel file. textarea comes out as "undefined undefined" . Could you help?
HTML CODE:
<div class="example">
<form enctype="multipart/form-data">
<input id="upload" type=file name="files[]">
</form>
<textarea
id="data"
class="form-control text-area-style"
rows=35
cols=120>
</textarea>
</div>
JS CODE:
function ExcelToJSON() {
var list;
document.getElementById("upload").addEventListener("change", handleFileSelect, false);
this.parseExcel = function(file) {
var reader = new FileReader();
reader.onload = function(e) {
var data = e.target.result;
var workbook = XLSX.read(data, {
type: "binary"
});
workbook.SheetNames.forEach(function(sheetName) {
// Here is your object
var XL_row_object = XLSX.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
var json_object = JSON.stringify(XL_row_object);
list = JSON.parse(json_object);
console.log(list);
jQuery().val(json_object);
list.forEach(function() {
$('#data).append(' < input name = "accesories"
type = "checkbox"
value = "'+list.id+'" / > '+list.name+' < br / > ');
});
})
};
reader.onerror = function(ex) {
console.log(ex);
};
reader.readAsBinaryString(file);
};
};
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
var xl2json = new ExcelToJSON();
xl2json.parseExcel(files[0]);
}
list.forEach(function() {
$('#data).append(' < input name = "accesories"
type = "checkbox"
value = "'+list.id+'" / > '+list.name+' < br / > ');
});
})
list does not have the attributes id and name (are undefined), you are iterating over list but you are not using the iterated item.
list.forEach(function(item) { // <= forEach calls for every list item this function with the item as argument
$('#data).append(' < input name = "accesories"
type = "checkbox"
value = "'+item.id+'" / > '+item.name+' < br / > ');
});
})
Hint:
Use the build in Browser Debugger it helps a lot, to understand JS.
With Chrome press F12 and set a breakpoint in the foreach function, then execute your code and it will break on the given line, then you will see all variables in your scope. (In your case you will se that list is an array and don't have id and name as property)

Javascript handling multiple files upload

I'm working on a project with the following steps:
Creating the form with multiple images upload
Previewing, remove images on queue before upload
Handling the file input value before submit
Here is my code
var fileList = [];
function toObject(arr) {
var rv = {};
for (var i = 0; i < arr.length; ++i)
rv[i] = arr[i];
return rv;
}
//Image prev
// Multiple images preview in browser
var imagesPreview = function (input, imageContainer) {
if (input.files) {
var filesAmount = input.files.length;
$(imageContainer).html('');
for (i = 0; i < filesAmount; i++) {
var reader = new FileReader();
reader.onload = function (event) {
var html = '<div class="image-item col-sm-6 col-md-4 col-lg-3"><div class="image-wrapper">' +
' <img src="'
+ event.target.result + '"/></div></div>';
$(html).appendTo(imageContainer);
}
var files = input.files;
fileList.push(files[i]);
reader.readAsDataURL(input.files[i]);
}
input.files = toObject(fileList);
}
};
$('#input-image').on('change', function () {
imagesPreview(this, '.image-container');
});
<div class="image-item">
<!-- input the image from user -->
<input id="input-image" type="file" name="photos[]" multiple>
<hr>
<div class="image-container row">
<!-- Previewing the image thumbnail -->
</div>
</div>
My questions: Can I set the value of the input-image with fileList variable because I set it but error occurs
Sry, a bit tired, will not go into depth or solve the hole thing...
There is only one way to change the value of file inputs and that is with another FileList instance. the only way you can get them is with some new api's so it won't work in all browsers. I made a function to help you with that.
var fileList = [];
// only way to change input[type=file] value is with a other FileList instance
// and this is the only way to construct a new FileList
function createFileList(a) {
a = [].slice.call(Array.isArray(a) ? a : arguments)
for (var c, b = c = a.length, d = !0; b-- && d;) d = a[b] instanceof File
if (!d) throw new TypeError('expected argument to FileList is File or array of File objects')
for (b = (new ClipboardEvent('')).clipboardData || new DataTransfer; c--;) b.items.add(a[c])
return b.files
}
// This is what you got to do later when they remove a image
//
// this will trigger a change event so you maybe want to temporary
// turn off the change event listener
//
// input.files = createFileList(fileList)
// Image prev
// Multiple images preview in browser
function imagesPreview(input, imageContainer) {
$(imageContainer).empty();
var URL = window.URL || window.webkitURL;
var $html = $(
'<div class="image-item col-sm-6 col-md-4 col-lg-3">'+
'<div class="image-wrapper"> <img></div></div>'
);
$.each(input.files, function(i, file) {
var $clone = $html.clone()
// could be a good idea to revoke url also
$clone.find('img').attr('src', URL.createObjectURL(file))
$clone.appendTo(imageContainer);
fileList.push(file);
});
}
$('#input-image').on('change', function () {
imagesPreview(this, '.image-container');
});
The other solution is to append each file into a formdata and send the form using ajax

Jquery upload files when open button is pressed

i have the following code, the issue i have is that i am getting a error of e.originalEvent.dataTransfer is undefined.
my code is as follows
HTML
Select images: <input type="file" id='fileupload' name="userfile[]" multiple>
Javascript is as follows
var hot = $('#fileupload');
hot.change(function (e)
{
e.preventDefault();
var files = e.originalEvent.dataTransfer.files;
//send dropped files to Server
handleFileUpload(files,hot);
});
function handleFileUpload(files,obj)
{
for (var i = 0; i < files.length; i++)
{
var fd = new FormData();
var e = document.getElementById("child_id");
fd.append('userfile[]', files[i]);
var filename=files[i].name;
var status = new createStatusbar(obj,files[i]); //Using this we can set progress.
status.setFileNameSize(files[i].name,files[i].size);
sendFileToServer(fd,status,filename);
}
}
The attribute files belongs to the input field. This you'll get by the target attribute.
If I test the setting above, I have success with this descriptor:
e.originalEvent.target.files
Then, files is an array of File objects, containing name, lastModifiedDate, type etc.

Loop through javascript for image previews

I'm currently getting to grips with html5 API image uploading and I'm a bit stuck with some javascript (way out my comfort zone) involved.
This is a snippet of my upload table (it also involves data collection for each image not shown here for things like renaming the image etc):
<tr>
<td>Image '.$i.':</td><td><output id="display'.$i.'"></output></td>
</tr>
<tr>
<td>Choose Image:</td>
<td><input name="file'.$i.'" type="file" id="file'.$i.'" accept="image/*" /></td>
</tr>
$i is a php counter, the user selects how many photos they will upload and it creates that many image boxes.
This is the javascript used to show an image preview:
document.getElementById('file1').addEventListener('change', handleFileSelect, false);
function handleFileSelect(evt) {
var files = evt.target.files;
var f = files[0];
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
document.getElementById('display1').innerHTML = ['<img src="', e.target.result,'" title="', theFile.name, '" width="100" />'].join('');
};
})(f);
reader.readAsDataURL(f);
}
My question is, being a javascript novice, is there a simple way to loop the script for each image. Currently it will only show the preview for 'file1', is there a way to change the '1' to something like $i, $i++ used for php loops? lets say the number of image boxes is stored as the php varible $totelboxes
EDIT: this is where I am so far:
var upFiles = document.getElementsByClassName('upFile');
for(var i = 0; i < upFiles.length; i++)
{
upFiles[i].addEventListener('change', handleFileSelect, false);
function handleFileSelect(evt) {
var files = evt.target.files;
var f = files[0];
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
document.getElementById('display'+i).innerHTML = ['<img src="', e.target.result,'" title="', theFile.name, '" width="100" />'].join('');
};
})(f);
reader.readAsDataURL(f);
}
}
You can us class names (document.getElementsByClassName) to do work for all your input file fields, little bit of jquery(not necessary)
document.getElementsByClassName('fileClassName').addEventListener('change', handleFileSelect, false);
function handleFileSelect(evt) {
var files = evt.target.files;
var f = files[0];
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
var relativeid= $(this).attr('id').replace("file","");
document.getElementById('display'+relativeid).innerHTML = ['<img src="', e.target.result,'" title="', theFile.name, '" width="100" />'].join('');
};
})(f);
reader.readAsDataURL(f);
}
You can give all your file inputs a class, then use document.getElementsByClassName and a for loop. (Note, for this to work in IE 8- you may need a shim, although you've probably forgone IE8 anyway by using addEventListener. See javascript document.getElementsByClassName compatibility with IE)
For example:
HTML:
<input id="file1" ... class="upFile" />
<input id="file2" ... class="upFile" />
JavaScript:
var upFiles = document.getElementsByClassName('upFile');
for(var i = 0; i < upFiles.length; i++)
{
upFiles[i].addEventListener(/*...*/);
}
Or, you can use jQuery for this, using your existing HTML and matching the first part of the ID:
$('input[type="file"][id^="file"]').change(handleFileSelect);
This matches all input elements with a type of "file" and an ID starting with "file".

Javascript Image Preview for page with lots of forms

I have a bunch of forms on a page that allow a user to edit information for each respective form. One of the inputs for the form is an image upload.
The forms are of the form below:
<form class="myForm" ...>
<div class="imagePreview"></div>
<input type="file" name="myImage" onchange="handleFiles(this.files)" />
</form>
And I have javascript to handle the image preview as follows:
function handleFiles(files) {
$(".obj").remove();
for (var i = 0; i < files.length; i++) {
var file = files[i];
var imageType = /image.*/;
if (!file.type.match(imageType)) {
continue;
}
var pic_div = document.getElementById("imagePreview");
var img = document.createElement("img");
img.classList.add("obj");
img.file = file;
pic_div.appendChild(img);
var reader = new FileReader();
reader.onload = (
function(aImg) {
return function(e) {
aImg.src = e.target.result;
};
}
)(img);
reader.readAsDataURL(file);
}
}
I want to replace the line:
var pic_div = document.getElementById("imagePreview");
with the appropriate line. This is where I am getting confused. I don't know how to refer to the div of class "imagePreview" for THIS FORM of class myForm.
Any help is much appreciated.
The problem is that you're getting the div with the Id imagePreview, when the div in the form have the imagePreview CSS class, what you can do is either give the div the required id, more less like this:
<div id="imagePreview"></div>
Or, if you will have multiple divs with the same class get them using jQuery like this:
$(".imagePreview").each(function(index){
//Do Something
});
Or:
var pic_div = $(".imagePreview")[0]

Categories

Resources