FileReader doesnot work without choosing a file - javascript

I have used FileReader to read the selected file using javascript. Here is the code
HTML:
<img id="preview" ng-src="{{user_picture}}" ng-click="triggerUpload()" alt="" width="160" height="160" class="img-thumbnail" />
<input type="file" onchange="angular.element(this).scope().viewImage(this.files)" accept="image/jpg,image/jpeg,image/png" id="fileInput" name="filedata" />
SCRIPT:
$scope.triggerUpload = function () {
show_image();
}
$scope.list = [];
$scope.viewImage = function (file) {
show_image(file);
}
function show_image(image) {
var fileuploader = angular.element("#fileInput");
fileuploader.on('click', function () {
if (image && image[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#preview').attr('src', e.target.result);
}
reader.readAsDataURL(this.files[0]);
}
})
fileuploader.trigger('click');
}
This works fine when I select an file from the upload dialog box. But, when I click 'Cancel' or exit the uploader without selecting any file, I get the error below.
Uncaught TypeError: Failed to execute 'readAsDataURL' on 'FileReader':
parameter 1 is not of type 'Blob'.
How to solve this problem??

How to solve this problem??
Don't call show_image when user selects cancel
function show_image(image) {
if (image && image[0] && this.files.length) {
var reader = new FileReader();
reader.onload = function (e) {
$('#preview').attr('src', e.target.result);
}
reader.readAsDataURL(this.files[0]);
}
}

The condition above checks for image && image[0] which (if our guess is correct without more code to explain it) check for this variable to be non-null.
However you are calling readAsDataURL() on this.files[0]; this variable has nothing to do with image, and most likely you are not setting it or it is not a filename when the user has pressed cancel.
Without more code, we cannot guess a more accurate answer...

Related

FileReader event listener cannot be called more than once [duplicate]

This question already has answers here:
How to detect input type=file "change" for the same file?
(22 answers)
Closed 2 years ago.
I have the following Typescript function that when called opens a window to request a file, and after the user makes a selection it prints in the console the file contents.
The first time it works fine, but the problem is that if I call it twice, it doesn't work. The second time it opens the window, but when the file is selected it does nothing. What is wrong with this function?
<input id="file-input" type="file" name="name" style="display: none;" />
printFile(){
var input = document.getElementById('file-input');
input.addEventListener('input', () => {
var uploadedFile = (input as HTMLInputElement).files[0];
var reader = new FileReader();
reader.addEventListener('load', () => {
console.log(reader.result);
});
reader.readAsText(uploadedFile);
});
input.click();
}
You are adding a listener to FileReader and then instantiating it again. The correct way of working should look like (a similar sample but using images):
HTML
<input
#fileInput
type="file"
accept="image/png, image/jpeg"
(change)="handleChosenFile($event)"
/>
Typescript
handleChosenFile(event: Event) {
const target = event.target as HTMLInputElement;
if (target.files && target.files.length) {
this.selectedFile = target.files.item(0);
const reader = new FileReader();
reader.readAsDataURL(this.selectedFile);
reader.onload = () => {
// Your function
};
} else {
// Your alert to "no file selected"
}
}
reader.addEventListener('load', () => {
console.log(reader.result);
});
should be
reader.addEventListener('load', (event) => {
console.log(event.target.result);
});

Javascript inline script onchange not working

i'm having a problem on making my code to adjust to my web server, because of the security purposes, all inline javascript code to my html is not allowed.
everything is already okay i'm just having a hard time converting my other code to pure javascript
Here is my existing code,,,
<label class=qrcode-text-btn><input type=file accept="image/*" capture=environment id="openQRCamera" tabindex=-1></label>
the original code is this
<label class=qrcode-text-btn><input type=file accept="image/*" capture=environment onchange="openQRCamera(this);" tabindex=-1></label>
the onchange is not working because it is inline in the html.
this function needs to open a camera and detect if there is a qr that exists.
here is what i have now on converting it.
document.querySelector("#openQRCamera").addEventListener('onchange', (node) => {
var reader = new FileReader();
reader.onload = function() {
node.value = "";
qrcode.callback = function(res) {
if(res instanceof Error) {
alert("There is no QR detected");
} else {
node.parentNode.previousElementSibling.value = res;
}
};
qrcode.decode(reader.result);
};
reader.readAsDataURL(node.files[0]);
});
here is the original code
function openQRCamera(node) {
var reader = new FileReader();
reader.onload = function() {
node.value = "";
qrcode.callback = function(res) {
if(res instanceof Error) {
alert("There is no QR detected");
} else {
node.parentNode.previousElementSibling.value = res;
}
};
qrcode.decode(reader.result);
};
reader.readAsDataURL(node.files[0]);
}
i am using this website as my source of code, everything is working fine in my localhost, but the server is just strict, and i think that's normal for all the websites.
https://www.sitepoint.com/create-qr-code-reader-mobile-website/
i just been stuck and try to do other solution like adding event listener, and append of input just by using jquery, but it's not working. thanks in advance.
The event listener you are using is faulty, instead of listenning to 'onchange' you have to listen to 'change' like so:
document.querySelector("#openQRCamera").addEventListener('change', () => {
//remove the node as parameter and get it with javascript:
var node = document.getElementById('openQRCamera');
..

Getting Image For Later Use

I am building a website where users can upload a picture, and then it will be displayed. I will need to set this image as their profile picture later on, and I don't have the slightest clue about how to do it. Thank You! Here is my code:
<input id="inp" type='file' accept="image/*"onchange="readURL(this);" /><br>
<img id="blah"/>
<script type="text/javascript">
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#blah')
.attr('src', e.target.result)
.width(150)
.height(150);
};
reader.readAsDataURL(input.files[0]);
}
}
</script>
I didn't really understand your question, you could save the data in a variable and then use that variable when you have to post the image, you should avoid ever storing images directly in the database, instead store references to them.
But if you want to simply display the image after selecting it, you can do something like this:
let input = $('input'),
img = $('img'),
reader = new FileReader();
function readFile(e) {
reader.onload = function(e) {
img.attr('src', e.target.result)
}
reader.readAsDataURL(e.target.files[0])
}
input.on('change', readFile)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="inp" type='file' accept="image/*"/>
<img/>
However, if you want to save the image permamently on a database you're gonna have to learn how back-ends work and maybe set up a Restful API.

Vue - button on click submits a form

I have a component where a user can upload an image, and I would like to also add a feature of removing an image. I have added a button which removes the current image, but the problem with it is that the form is getting submitted as well, and I would like to avoid that. I just need to remove the current image if it exists. This is the script:
<template>
<div class="Image-input">
<div class="Image-input__input-wrapper">
<h2>+</h2>
<input #change="previewThumbnail" class="Image-input__input" name="image" type="file">
</div>
<div class="Image-input__image-wrapper">
<i v-show="! imageSrc" class="icon fa fa-picture-o"></i>
<img v-show="imageSrc" class="Image-input__image" :src="imageSrc">
<button v-show="imageSrc" #click="removeImage">Remove image</button>
</div>
</div>
</template>
<script>
export default {
props: ['imageSrc'],
methods: {
previewThumbnail: function(event) {
var input = event.target;
if (input.files && input.files[0]) {
var reader = new FileReader();
var vm = this;
reader.onload = function(e) {
vm.imageSrc = e.target.result;
}
reader.readAsDataURL(input.files[0]);
}
},
removeImage: function removeImage(e) {
this.imageSrc = '';
}
}
}
</script>
I have tried with placing event.preventDefault() in the removeImage method, but then, if I after removing image try to upload the same one again it won't upload. Not sure what to do about it?
If you have a button inside a form, it has a default type of "submit". To prevent that from happening, you will have to set type="button" as follows:
<button type="button" v-show="imageSrc" #click="removeImage">Remove image</button>
Reference: Can I make a <button> not submit a form?
Edit: Solution for the second problem mentioned in comments #1 to #5
Please modify your reader.onload function as follows:
reader.onload = function(e) {
vm.imageSrc = e.target.result;
console.log("Clearing file input");
document.querySelectorAll('input[type=file]').forEach(element => {
element.value = "";
});
}
As you can see, I am printing out a console log for debugging (which you can remove), then proceeding to select all file inputs and resetting its value. This clears the selected file.
Note: This clearing function happens after the file is read into memory. If you want it on remove function, you can do as follows:
removeImage: function removeImage(e) {
this.imageSrc = "";
console.log("Clearing file input");
document.querySelectorAll('input[type=file]').forEach(element => {
element.value = "";
});
}
The choice is yours, whether you want to clear the file name after reading into memory or if you want to keep it on screen. Let me know if it works!
Another note: If you have any other <input type="file"> in your app, even that will get cleared. But I assume you would have read it into memory and kept it in some local variables. To avoid this, you need to modify the document.querySelectorAll function to target only the relevant input by giving it a class or id.

Javascript: onload event not reaching for javascript's FileReader API

I need to create extract the signature of a file at the client level itself so as to positively determine its file type. Below is my file input object:
<input id="test1" type="file">
I wrote the following javascript code against it:
var fileInput = document.getElementById('test1');
fileInput.addEventListener('change', function(e) {
console.log("file selected");
var reader = new FileReader();
reader.onload = function(e) {
console.log("loaded");
var file_slice = gcUploadFile.slice(0,4);
console.log(file_slice);
var arr_buffer = reader.readAsArrayBuffer(file_slice);
console.log(arr_buffer);
}
});
Check out the fiddle for the above.
The trouble I am having is that my code does not even enters the onload fucntion.
What am i doing wrong?
Note: I am coding only using plain javascript but i am open to use Google Closure.
Why would it reach the onload handler, nothing is ever read by the FileReader.
You have to pass the file to the fileReader by reading it as something
var fileInput = document.getElementById('test1');
fileInput.addEventListener('change', function(e) {
console.log("file selected");
var reader = new FileReader();
reader.onload = function(e) {
console.log("loaded");
var file_slice = gcUploadFile.slice(0,4);
console.log(file_slice);
var arr_buffer = reader.readAsArrayBuffer(file_slice);
console.log(arr_buffer);
}
reader.readAsBinaryString(e.target.files[0]);
});

Categories