How to get results of File reader - javascript

So I have an onchange event in my html which gets an image from the user and need to convert it to a data url in order to send over socket.io and store in the database. How do I get the results of my file reader object. I dont know how to pass in a callback
What I need to do is get a callback function into the file reader onload event so that I can set my picture variable to the data url to then send over the socket. Just need help in getting the results from the file reader to my global variable
// HTML
<input type = 'file' (change) = "setpreview($event)" value = 'upload photo'>
// the js code.
setpreview(event) {
var img = <File>event.target.files[0];
var reader = new FileReader();
reader.onload = function() {
console.log(reader.result);
}
reader.readAsDataURL(img);
}

You got it just assign the result to a scoped variable and use it in template
srcImg = null; //declare this
setpreview(event) {
const comp = this;
const img = <File>event.target.files[0];
const promise = new Promise((resolve) => {
const reader = new FileReader();
reader.onload = function () {
resolve(reader.result);
}
reader.readAsDataURL(img);
});
promise.then(img => {
comp.srcImg = img;
// if you want to do anything with img you can do it here
});
}
<input type = 'file' (change) = "setpreview($event)" value = 'upload photo'>
<img [src]="srcImg" *ngIf="srcImg" />
Updated Stackblitz: https://stackblitz.com/edit/angular-tkbbdh

Related

HTML 5 Filereader Not returning Base64 URL Onloadend

I am using the following script for reading image data as base64 url.
function getBase64(incomingfile) {
var reader = new FileReader;
reader.readAsDataURL(incomingfile);
reader.onloadend = ()=>{
console.log(reader.result);
}
}
This is working fine and printing the result on console. But when I try to apply this below code
function getBase64(incomingfile) {
var reader = new FileReader;
reader.readAsDataURL(incomingfile);
reader.onloadend = ()=>{
return reader.result;
}
}
I am not getting the result of this function after calling. What should I do to get return value of Filereader.
the file The FileReader methods work asynchronously but don't return a Promise so when attempting to retrieve the result immediately after calling a method will not work
try this
let logBase64 = "";
function getBase64(incomingfile) {
var reader = new FileReader();
reader.readAsDataURL(incomingfile);
return new Promise((resolve, reject) => {
reader.onloadend = () => {
resolve(reader.result);
};
}).then((result) => {
logBase64 = result;
console.log(logBase64);
});
}

How to work with the url of a fileReader object?

Hello! I'am trying to make it work a function called loadDocument, who need a url of the loaded files from the user local computer to work. I'm writing an API to load document from local user computer, and show it on a web reader.
This is my upload button :
<input type="file" id="input" onchange="module.onLoadSelection();" alt="Browse" name="upload"/>
This is my function without fileReader :
var onLoadSelection = function () {
var select = document.getElementById('input');
if (select && select.value) {
var id= '';
var url = select.files.item(0).name;
module.loadDocument(url,id);
}
};
This is my function with fileReader :
var loadTest = function (input) {
var file = document.querySelector('input[type=file]').files[0];
console.log("file loaded! ->", file); // i can read the obj of my file
var reader = new FileReader();
var id = ''; // don't need rightnow
var url = reader.readAsDataURL(file);
console.log("url :", url); // show me undefined....
module.loadDocument(url,id);
}
What i am trying is to get the url of the loaded file from user computer to get my function loadDocument working. She need a url parameter to work.
loadDocument is an API function, i assume i can't get the filepath of my user due to security reason.
What do i need to change/update on my loadDocument(); function to work?
Edit : In fact, nothing to change. The correct way to read my file was :
<input type="file" id="input" onchange="module.onLoadSelection(this.files);" alt="Browse" name="upload"/>
var onLoadSelection = function (files) {
if (files && files.length == 1) {
var id = '';
var url = URL.createObjectURL(files[0]);
module.loadDocument(url,id);
}
};
Don't use a FileReader at all.
When you want to display a File (or a Blob) that is in the browser's memory or on user's disk, then all you need is to generate an URL that do point to this memory slot.
That's exactly what URL.createObjectURL(blob) does: it returns a Blob URI (blob://) that points to the data either in memory or on the disk, acting exactly as a simple pointer.
This method has various advantages over the FileReader.readAsDataURL() method. To name a few:
Store the data in memory only once, when FileReader would need it at reading, then generate a copy as an base64 encoded, and an other one at displaying...
Synchronous. Since all it does is to generate a pointer, no need to make it async.
Cleaner code.
const module = {
loadDocument: (url) => {
document.body.append(
Object.assign(
document.createElement('iframe'),
{ src: url }
)
)
}
};
document.querySelector('input[type=file]').addEventListener('input', function (evt) {
var file = this.files[0];
var url = URL.createObjectURL(file);
module.loadDocument(url);
});
<input type="file">
function PreviewFiles(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
//alert(e.target.result);
$('#pclogo').prop('src', e.target.result)
.width(200)
.height(200);
var base64result = e.target.result.split(',')[1];
$('input[name="logo"]').val(base64result);
};
reader.readAsDataURL(input.files[0]);
}
}
File objects have a readAsDataURL method.
Use that.
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.addEventListener("load", function () {
doSomethingWithAUrl(reader.result);
}, false);
if (file) {
reader.readAsDataURL(file);
}

How to access a local variable in filereader onload callback

I am doing a file upload operation in React, and I need to read the file uploaded from the user and do some state changes according to this file. What I have right now is shown below and I need to need to access the variable startInt within the onload callback, but it is still not defined here using the IIFE
const file = document.getElementById("fileUpload").files[0];
if (file) {
const reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = ((theFile) => {
const form = document.getElementById('fileUploadForm');
const start = datetimeToISO(form.Start.value);
const startInt = new Date(start).getTime();
return (e) => {
console.log(e.target.result);
//startInt is not defined here
}
})(file);
}
I followed this guide if it helps: https://stackoverflow.com/a/16937439/6366329
If you could point out my mistake that would be great. Many thanks in advance
you can access local var (but not class const like this.state.* or this .props.*).
so something like this you need:
var file = document.getElementById('inputID').files[0]
var Images = this.props.motherState.Images // Images is array
var reader = new FileReader();
reader.readAsDataURL(file); //
reader.onload = function () {
//console.log(reader.result);
if (file.type.match(/image.*/))
Images.push(reader.result) // its ok
// but this.props.motherState.Images.push(reader.result)
// return error like this:
// Images not define in this.props.motherState.Images
};
reader.onerror = function (error) {
//console.log('Error: ', error);
};

typescript angular 2 - creating own blob from input corrupts data

For learning purposes, I want to use the html input tag to select a jpeg image, retrieve the File Object, load it with fileReader and use the retrieved image string (base64) to create a new blob/file.
the service can upload the original file retrieved from the input just fine. However using my newFile the file get's corrupted and the file size somehow is larger.
I figure I'm doing something wrong with the blob constructor?
I'm using angular2 in typescript
<input type="file" (change)="onFileChanged($event)">
onFileChanged(event){
if (event.target.files && event.target.files[0]) {
let file = event.target.files[0];
let newFile;
let fr = new FileReader();
fr.onload = (event:any)=>{
let base64 = event.target.result
let img = base64.split(',')[1]
let blob = new Blob([window.atob(img)],{type:'image/jpeg'})
newFile = this.blobToFile(blob,'test')
}
fr.readAsDataURL(file)
console.log(file)
console.log(newFile)
this.service.upload(newFile).subscribe()
}
}
blobToFile(blob: Blob, fileName: string): File {
let b: any = blob;
b.lastModified = moment.now();
b.lastModifiedDate = new Date();
b.name = fileName;
b.webkitRelativePath="";
return <File>blob
}
EDIT------------
After finding out that fileReader is asynchronous, i've adjusted it a little bit and indeed the problem is with the blob constructor.
loggin the both the target.result of original file and new one revealed that the base64 as been transmuted. Any ideas why?
if (event.target.files && event.target.files[0]) {
let file = event.target.files[0];
let base64: string = null;
if (/^image\//.test(file.type)) {
let reader = new FileReader();
reader.onload = (e: any) => {
console.log(e.target)
base64 = e.target.result
let img = base64.split(',')[1];
let blob = new Blob([img], { type: 'image/jpeg' })
console.log(blob);
let fr = new FileReader()
fr.onload = (event: any) => {
console.log(event.target)
}
fr.readAsDataURL(blob)
}
reader.readAsDataURL(file);
}
Modify your function like this. Because FileReader is asynchronous, to process the result, you need to do it inside the onload callback, but here, you are uploading the file outside of onload which at that point, is undefined or whatever initial value it contains.
onFileChanged(event){
if (event.target.files && event.target.files[0]) {
let file = event.target.files[0];
let newFile;
let fr = new FileReader();
fr.onload = (event:any)=>{
let base64 = event.target.result
let img = base64.split(',')[1]
let blob = new Blob([window.atob(img)],{type:'image/jpeg'})
newFile = this.blobToFile(blob,'test')
this.service.upload(newFile).subscribe()
}
fr.readAsDataURL(file)
console.log(file)
console.log(newFile) // Either prints undefined or whatever initial value it contains
}
}
I am suspecting your code:
onFileChanged(event){
if (event.target.files && event.target.files[0]) {
let file = event.target.files[0];
let newFile;
let fr = new FileReader();
fr.onload = (event:any)=>{
let base64 = event.target.result
let img = base64.split(',')[1]
let blob = new Blob([window.atob(img)],{type:'image/jpeg'})
newFile = this.blobToFile(blob,'test')
}
fr.readAsDataURL(file)
console.log(file)
console.log(newFile)
this.service.upload(newFile).subscribe()
}
}
onFileChanged(event) and (event:any), these two 'event' mean different objects. event in onFileChanged is the event object of onFileChanged. event in fr.onload is the event object of FileReader.onload. Don't you think it is confusing and might cause cross reference?

How to get the filename from the Javascript FileReader?

I'm using the Javascript FileReader to load an image in the browser:
e = e.originalEvent;
e.dataTransfer.dropEffect = 'copy';
this.documentFile = e.dataTransfer.files[0];
var reader = new FileReader();
reader.onloadend = function () {
if (reader.result) {
console.log(reader);
$('#theImage').attr('src', reader.result);
}
};
reader.readAsDataURL(this.documentFile);
This works fine. I now want to get the original filename of the image, but I've got no clue how and looking around the internet I can't find anything either?
Does anybody know how I can get the filename through the FileReader? All tips are welcome!
This is prob not the best solution, BUT it worked for me.
var reader = new FileReader();
reader.fileName = file.name // file came from a input file element. file = el.files[0];
reader.onload = function(readerEvt) {
console.log(readerEvt.target.fileName);
};
Not the best answer, but a working one.
I just faced the same issue, here's how I fixed it:
Using FileReader
const reader = new FileReader();
reader.readAsDataURL(event.target.files[0]); // event is from the HTML input
console.log(event.target.files[0].name);
The selected answer will work, but I personally prefer to prevent assigning unknown properties to existing objects.
What I do is using the built-in Map object to store connections between FileReader and its File. It works great, because Map allows the key to be anything, even an object.
Consider this example with drag&drop on the window, where multiple files can be dropped at the same time:
// We will store our FileReader to File connections here:
const files = new Map();
window.addEventListener('drop', e => {
e.preventDefault();
for (const file of e.dataTransfer.files) {
const reader = new FileReader();
files.set(reader, file);
reader.addEventListener('load', e => {
// Getting the File from our Map by the FileReader reference:
const file = files.get(e.target);
console.log(`The contents of ${file.name}:`);
console.log(e.target.result);
// We no longer need our File reference:
files.delete(e.target);
});
reader.readAsText(file);
}
});
window.addEventListener('dragover', e => {
e.preventDefault();
});
And voilĂ , we made it without altering our FileReader objects!
I got the filename and filesize through the FileReader this way
First of all, the reader is a javascript FILE API specification that is so useful to read files from disc.
In your example the file is readed by readAsDataURL.
reader.readAsDataURL(this.documentFile);
var name = this.documentFile.name;
var size = this.documentFile.size;
I tried on my site where use this.files[0] instead and worked fine to catch the name and the size with jQuery into an input element.
reader.readAsDataURL(this.files[0]);
$("#nombre").val(this.files[0].name);
$("#tamano").val(this.files[0].size);
I tried the solution of #Robo Robok but was unable to get this to work in my Angular Application. With this as inspiration I came up with the following and wonder if this is a correct approach. Me, I'm a bit skeptic because each upload gets there own FileReader
export class ImageFileUpload {
imageData: any;
imageName!: string;
fileReader!: FileReader;
}
selectedFiles!: FileList | null;
previews: Array<ImageFileUpload> = [];
uploadRenewals(event: any) { // event of html
const target = event.target as HTMLInputElement;
this.selectedFiles = target.files;
if (this.selectedFiles) {
const numberOfFiles = this.selectedFiles.length;
for (let i = 0; i < numberOfFiles; i++) {
const currentSelectedFile = this.selectedFiles[i];
const newImageFile = new ImageFileUpload();
newImageFile.imageName = currentSelectedFile.name;
newImageFile.fileReader = new FileReader();
newImageFile.fileReader.onload = (e: any) => {
newImageFile.imageData = e.target.result;
};
newImageFile.fileReader.readAsDataURL(currentSelectedFile);
this.previews.push(newImageFile);
}
}
}
}
HTML Page
<input #fileInput (change)="uploadRenewals($event)" multiple type="file">
<div class="slider">
<div *ngFor="let preview of previews; let idx = index">
<img [src]="preview.imageData" [alt]="preview.imageName">
</div>
</div>
One other way is to modify the FileReader() object instance with your own desired property. Adding a key like reader.myOwnFileName gets you access to that in the onload callback.
const reader = new FileReader();
reader.onload = function() {
console.log("Loaded file '" + reader.myOwnFileName + "' contents: ");
console.log(reader.result); // output file contents of chosen file.
};
reader.readAsText(this.files[0]); // use readAsText(), readAsDataURL() or other method.
// make your own key on the object instance:
reader.myOwnFileName = this.files[0].name;
If you want the filename to a variable:
var filename;
var reader = new FileReader();
reader.onloadend = function () {
if (reader.result) {
console.log(reader);
$('#theImage').attr('src', reader.result);
filename = reader.result;
}
};
reader.readAsDataURL(this.documentFile);
If you want it to run in a function:
var reader = new FileReader();
reader.onloadend = function () {
if (reader.result) {
console.log(reader);
$('#theImage').attr('src', reader.result);
myfunctionafter(reader.result);
}
};
reader.readAsDataURL(this.documentFile);
If you want to get the info out inside another function:
var reader = new FileReader();
var filename = reader.onloadend = function () {
if (reader.result) {
console.log(reader);
$('#theImage').attr('src', reader.result);
return reader.result;
}
};
reader.readAsDataURL(this.documentFile);
There might be a problem when your reader.onloadend might finish before the function you are running it from. Then you should do two functions and trigger the myfunctionafter(reader.result); from inside
Or you could simply get the src after
var filename = $('#theImage').attr('src');

Categories