I'm using p-fileUpload in Angular 6.0.0 app, for uploading the image files (In this case multiple images files). It has an event handler (uploadHandler) for the uploaded files.
<p-fileUpload multiple="true" name="myfile[]" accept="image/*" [auto]="true"
customUpload="true" chooseLabel="Select" (uploadHandler)="uploadImage($event)">
</p-fileUpload>
The files are getting uploaded correctly, but I'm not able to generate the base64 code when looping over the e.files array, because reader.onloadend is not firing. I've searched this firing issue and found some related questions but the solution of them is not solving my problem. Below is the code I've written for multiple image file upload -
uploadImage(e: any) {
if (e && e.files.length) {
const reader: FileReader = new FileReader();
e.files.forEach((i: File, j: any) => {
reader.onloadend = (ev: any) => {
console.log('inside??');
// Console is not triggered
};
// reader.readAsDataURL(...);
this.cdr.markForCheck(); // For outside zone detection
});
}
}
Please help me with this problem.
I'm using this same code for single image upload (so I don't need forEach loop there) inside the same app and it is working in all other places unlike in this case.
Related
I am trying to make a feature for my web application that allows the user to upload multiple images as a part of a blog post, then view them later on a page that shows a list of all blog posts. What I am trying to do is, allow the user to upload multiple images and save those images to localStorage. Currently I am looping through all the image files the user has uploaded, then adding a new fileReader to each one. In order to add them to the localStorage, I know I have to make the key value of each image different (i.e. img1=the first image, img2=the second image, etc.) As per the code below, I am changing the key value for each image uploaded using a for loop, and setting it to img${i}.
However when I try to add a "load" event listener onto each fileReader component to read each individual image file in order to save it onto localStorage, because it is a "load" event the value of the "i" is different. So as a result, I can only save the final image that has been uploaded (i.e. img3). I am assuming this is caused by the code that is within a "load" event so that it will only consider the final "i" value when all the files have loaded. Would there be a way around this issue? Any help towards the right direction is greatly appreciated. I am trying to achieve this in pure javascript so no jquery please. Thank you.
HTML
<!--Upload images-->
<input type="file" id="filetag" multiple accept=".jpg,.jpeg,.png,.gif">
<img id="preview">
Javascript
const fileSelector=document.getElementById('filetag');
const display = document.getElementById("preview");
fileSelector.addEventListener('change',(e)=>{
//gets all the files uploaded
let fileList = e.target.files;
console.log(fileList)
for(i=0;i<fileList.length;i++){
//add a new fileReader for each element
let reader = new FileReader();
reader.addEventListener("load", () =>{
//store each uploaded image into localStorage
localStorage.setItem(`img${i}`,reader.result)
console.log(i)
})
reader.readAsDataURL(fileList[i]);
}
})
First, I don't think that you should use LocalStorage for this. Besides LocalStorage size is limited. In case you have a back-end, those images should be saved in the server, and then just load them with the URL, like any normal website.
In any case, I answer your question. Instead of using an array (and having that problem with the index), turn it into an object and then use the object key:
let fileList = e.target.files;
let files = {};
let index = 0;
for(let file of files) {
files[index] = file;
index ++;
}
// Now iterate object instead of array
Object.keys(files).forEach( key => {
let reader = new FileReader();
reader.addEventListener("load", () =>{
localStorage.setItem(`img${key}`,reader.result)
})
reader.readAsDataURL(files[key]);
});
Maybe naive question but I'm wondering this:
I have an html input allowing me to find a local file on my computer. <input type="file" id="importFile">
From this input, i create a FileReader in js to display the text file content on my page
var search_file = document.getElementById("search_file")
search_file.addEventListener('change', function(){
var reader = new FileReader();
var tmp = [];
reader.readAsText(file_to_survey);
reader.onload = function(e) {
var contents = e.target.result;
//function to edit html thanks to content//
}, false);
This part is actually working well BUT if I edit or replace the file I targeted (with exact same file name), I'm not able to display the file without to search it again with the html input mentionned above.
Is there a way to keep trace of my file even after edition?
Many thanks for your help. I dug quiet a lot to solve my problem but maybe I'm thinking the wrong way. Any clue would be nice.
Because that's how the input type=file element works, and to my best knowledge there is no way for you to force the browser to automatically re-read a file from the user's hard drive without their express consent.
You can put the change handler of the file input in a separate function, and call that function when needed.
function loadFile () {
var reader = new FileReader();
reader.addEventListener('load', function () {
file = reader.result;
// Handle the changes here
console.log(file);
});
reader.readAsText(fileField.files[0]);
}
const fileField = document.getElementById('load'),
reloadBut = document.getElementById('reload');
let file;
reloadBut.addEventListener('click', loadFile);
fileField.addEventListener('change', loadFile);
<input type="file" id="load">
<button id="reload">Load</button>
A separate button is used to reload the file in this snippet, but you can call loadFile where ever you need, ex. in an interval or from some event handler knowing the file was changed etc.
Note: This works in Chrome only, other browsers seem to lose the reference to the file browsed into file input when the file is changed. Also, the file must be properly closed after saving, before reloading.
I am building a web interface that allows the user to upload a custom font. The problem is that I am unable to convert the font files (specifically, .ttf, .woff, and .woff2 files) to base64 via the FileReader.readAsDataUrl() so that I can then PUT these files via my API.
I can successfully reasAsDataUrl .png and .jpg files, and receive those files' data as a base64 encoded strings, no problem. However, when I try to do the same thing with a .ttf, .woff, or .woff2 file, reader.result is empty although the FileReader doesn't throw any error.
I am using input elements to allow the user to select a font:
<input type="file" accept="application/font-woff" onChange={handleUpload}/>
The handleUpload function looks like this:
handleUpload: () => (event: Object) => {
const { currentTarget: element } = event;
if (!element.files) { return; }
const file = element.files[0];
const reader = new FileReader();
reader.onerror = (error) => {
console.error('Error: ', error);
};
reader.readAsDataURL(file);
console.log(reader.result); // reader.result is empty
}
This is the file object that I am passing to the readAsDataURL function.
I figured it out :-)
readAsDataURL was working successfully but I was returning reader.result before the read was complete. I changed my code to include
reader.addEventListener('load', () => {
change(name, reader.result);
}, false);
and now it's working!
Additional info (edit): The reason why it was working for the image files was because in the onUpload function for those input components I was rendering a preview image which depended on the file being done loading... as a side effect of waiting for the file in order to render the preview, I was also ensuring that the file was loaded before I did anything with it afterwards. I was happy to realize this because if one day, for some reason, I removed the image preview piece, my image upload would have also broken!
My FileReader object is working perfectly to upload images. I'm tracking onload as well as other events, these all happen when I upload images:
fileReader = new FileReader();
fileReader.onloadstart = (e) => {
window.alert('fileReader onloadstart');
window.alert(e);
};
// ... and the same for onprogress, onabort, onerror, then finally:
fileReader.onload = (e) => {
window.alert('arrived to fileReader.onload!');
// ...
};
I added cordova-plugin-media-capture to capture audio. I now need to use the existing fileReader.onload callback to upload it etc.
But no matter what I do, I cannot get fileReader.readAsDataURL to respond. Below is my code adapted from this answer about a similar problem, but it doesn't resolve it.
None of the fileReader events are firing, not even error. The fileReader.readAsDataURL function is available, yet when calling it all that happens is the screen briefly goes white and then I'm back at the page I was at before as if I had not done anything. None of the methods on fileReader show their alerts.
navigator.device.capture.captureAudio((files) => {
const file = files[0];
newFile = new File(
file.name,
file.localURL,
file.type,
file.lastModifiedDate,
file.size);
window.alert(newFile);
// --> [Object object]
window.alert(JSON.stringify(newFile));
// --> An object with name, localURL etc. See image.
window.alert(fileReader.readAsDataURL);
// --> function readAsDataURL() { [native code] }
fileReader.readAsDataURL(newFile); // nothing at all
})
The stringified newFile object is:
I've tried processing the file captureAudio gives in different ways:
resolveLocalFileSystemURL: https://ourcodeworld.com/articles/read/80/how-to-convert-a-image-from-the-device-to-base64-with-javascript-in-cordova
fileSystem.root.getFile as in https://groups.google.com/forum/#!msg/phonegap/uX_aDRKp72I/ZUbt0ThWVQkJ
But every time the same thing: when I arrive at readAsDataURL, nothing happens anymore. What could be wrong?
Edit: I forgot to mention some things:
tested on iOS device and simulator
cordova-plugin-file is installed
I am reading a local CSV file using a web UI, and the HTML5 FileReader interface to handle the local file stream. This works great.
However, sometimes I want the file being read to be updated continuously, after the initial load. I am having problems, and I think it might have something to do with the FileReader API. Specifically, after the initial file load, I maintain a reference to the file. Then, when I detect that the size of the file has increased, I slice off the new part of the file, and get a new Blob object. However, there appears to be no data in these new Blobs.
I am using PapaParse to handle the CSV parsing, though I don't think that is the source of the problem (though it may be).
The source code is too voluminous to post here, but here is some pseudocode:
var reader = new FileReader();
reader.onload = loadChunk;
var file = null;
function readLocalFile(event) {
file = event.target.files[0];
// code that divides file up into chunks.
// for each chunk:
readChunk(chunk);
}
function readChunk(chunk) {
reader.readAsText(chunk);
}
function loadChunk(event) {
return event.target.result;
}
// this is run when file size has increased
function readUpdatedFile(oldLength, newLength) {
var newData = file.slice(oldLength, newLength);
readChunk(newData);
}
The output of loadChunk when the file is first loading is a string, but after the file has been updated it is a blank string. I am not sure if the problem is with my slice method, or if there is something going on with FileReader that I am not aware of.
The spec for File objects shouldn't allow this: http://www.w3.org/TR/FileAPI/#file -- it's supposed to be like a snapshot.
The fact that you can detect that the size has changed is probably a shortcoming of an implementation.