I am trying to add property to file object. I am adding property like this (I am using Vue):
<input type="file" id="fileUpload" name="file" #change="setToUploadStatus" multiple>
setToUploadStatus method:
setToUploadStatus (event) {
let files = event.target.files
Array.from(files).forEach((file) => {
let id = this.randomString(10)
file.id = id
this.uploadStatus.push({
id: id,
name: file.name,
uploading: false,
uploaded: false
})
}
this.uploadFile(files)
}
uploadFile method:
async uploadFile (files) {
for (const file of files) {
// Upload file with axios
}
}
randomString method:
randomString (length) {
let text = ''
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length))
}
return text
}
My problem is it's not adding id property always. Sometime it's adding sometime not. Specially when many files are selected. Here is a log https://prnt.sc/kxsqhi
What am I doing wrong? Please help!
Converted to a snippet here:
setToUploadStatus(event) {
let files = event.target.files
Array.from(files).forEach((file) => {
let id = this.randomString(10)
file.id = id
this.uploadStatus.push({
id: id,
name: file.name,
uploading: false,
uploaded: false
})
}
this.uploadFile(files)
}
async uploadFile(files) {
for (const file of files) {
// Upload file with axios
}
}
randomString(length) {
let text = ''
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length))
}
return text
}
<input type="file" id="fileUpload" name="file" #change="setToUploadStatus" multiple>
First, from the code you've given there is nothing wrong with it. Perhaps the issue is coming from somewhere else.
Second, I see you want to give a unique id to every file. Generating a random string is fine, but there is still a possibility that two random strings will be the same. So here is a simple way to go about that.
new Vue({
el: "#app",
data: {},
methods: {
updateFile(event) {
let files = event.target.files
let uid = 0;
Array.from(files).forEach(file => {
file.id = ++uid;
console.log(file);
});
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<input type="file" multiple #input="updateFile" />
</div>
This implementation is simple.
Here is the JSFiddle Link: https://jsfiddle.net/clintonyeb/3qreb1L9/
Related
In my app, I have an Upload button that enables the user to search files and upload them. I also defined a textarea and I want the user to be able to paste the file that he copied and upload it that way (like you would do in an e-mail or whatsapp etc.). Right now, when I try to paste the file that I've copied, nothing happens and the file doesn't paste. My code is below. What should I do to upload files by paste?
HTML:
<div>
<button mat-stroked-button class="primary-fg" (click)="onFileUploadClick($event)">
<mat-icon>attach_file</mat-icon>
Upload
</button>
<mat-form-field appearance="fill">
<mat-label>Paste</mat-label>
<textarea matInput
cdkTextareaAutosize
#autosize="cdkTextareaAutosize"
cdkAutosizeMinRows="1"
cdkAutosizeMaxRows="5"
id="pasteArea"></textarea>
</mat-form-field>
<script>
window.addEventListener("paste", e => {
if (e.clipboardData.files.length > 0) {
const fileInput = document.querySelector("#fileInput");
fileInput.files = e.clipboardData.files;
}
});
</script>
</div>
<input hidden type="file" id="fileInput" #fileInput multiple />
TS:
onFileUploadClick(event: any) {
event.preventDefault();
const fileInput = document.getElementById('fileInput') as HTMLInputElement;
fileInput.value = '';
fileInput.onchange = () => {
let tempFiles: IAttachment[] = [];
for (let index = 0; index < fileInput.files.length; index++) {
const file = fileInput.files[index];
const fileSize = file.size / 1024 / 1024; // in MB
if (fileSize <= 5) {
tempFiles.push({ FileInfo: file });
}
else {
this._dialog.open(FuseSimpleDialogComponent, {
width: "400px",
data: {
title: "Uyarı",
message: "Dosya boyutu 5MB'den büyük olduğundan seçilemez. Dosya Adı: " + file.name
}
});
}
}
tempFiles.forEach(f => this.uploadFile(f));
};
fileInput.click();
}
/**
*
* #param file
*/
private uploadFile(file: IAttachment) {
if (file.FileData) return; //file already uploaded
let fileReader: FileReader = new FileReader();
let $that = this;
let data: any;
fileReader.onerror = function (): void {
//show error message
};
fileReader.onloadend = function (): void {
if (FileReader.prototype.readAsBinaryString) {
data = btoa(fileReader.result as string);
}
else { //support for IE
data = ($that as any).arrayBufferToBase64(fileReader.result);
}
file.Name = file.FileInfo.name;
file.FileData = data;
file.CreateDate = new Date();
file.CreateUser = $that.user;
let allFiles = $that.Attachments ? $that.Attachments.slice(0) : [];
allFiles.unshift(file);
$that.Attachments = allFiles;
$that.AttachmentsChange.emit(allFiles);
};
if (FileReader.prototype.readAsBinaryString) {
fileReader.readAsBinaryString(file.FileInfo);
}
else { //support for IE
fileReader.readAsArrayBuffer(file.FileInfo);
}
}
Careful with you approach, simply pasting a file into a textarea will do nothing as a text area is made to receive... text.
You need to have an input file somewhere on your component and an event listener on window for the paste event.
Then take the paste event and try to see if it includes a file, if yes, start the uploading process, if not, paste the text in the textarea.
This is how I would approach it.
In the code snippet below, I would like to get rid of the 'Upload' button and wanna invoke this 'Upload()' inside 'incomingfile()' function. Is there a way to invoke the "Upload()" function without clicking the button?
<input type="file" id="file-upload" (change)="incomingfile($event)"/>
<label for="file-upload">Upload file</label>
<button type="button" class="btn btn-info" (click)="Upload()">Upload</button>
incomingfile(event) {
this.file = event.target.files[0]
}
Upload() {
let fileReader = new FileReader()
fileReader.onload = e => {
this.arrayBuffer = fileReader.result
var data = new Uint8Array(this.arrayBuffer)
var arr = new Array()
for (var i = 0; i != data.length; ++i)
arr[i] = String.fromCharCode(data[i])
var bstr = arr.join('')
var workbook = XLSX.read(bstr, { type: 'binary' })
var first_sheet_name = workbook.SheetNames[0]
var worksheet = workbook.Sheets[first_sheet_name]
this.fileData = XLSX.utils.sheet_to_json(worksheet, { raw: false })
console.log(this.fileData)
}
fileReader.readAsArrayBuffer(this.file)
}
You will have to trigger the DOM Button element in the function incomingfile:
const el = document.getElementsByTagName('button');
el.click();
Unless I'm missing something from your description, think you just need to call Upload() function instead of having a user event trigger it, so just add it to your other function:
incomingfile(event) {
this.file = event.target.files[0];
Upload();
}
Why don't u call like below code
incomingfile(event) {
this.file = event.target.files[0];
this.Upload();
}
Yes called upload method into incomingFile method like shown below.
incomingfile(event) {
this.file = event.target.files[0]
upload();
}
thanks
I want to change name's file selected by input type=file, but it doesn't work.
This is my code:
$("document").ready(function() {
$('body').on('change', '#FileID', function() {
var name = document.getElementById('FileID');
name.files.item(0).name = Math.floor(Math.random() * 100000);
console.log('Selected file: ' + name.files.item(0).name);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id='FileID' class='class1' type='file' name='Images' value='' />
To change the name of a File object, you need to create a new File instance.
You can create one from a previous File object and it will act a simple wrapper over the data on disk.
The sketchier part is to update the <input type="file"> value to use this new File.
It is now possible through an hack as exposed in this answer of mine:
$('body').on('change', '#FileID', function(evt) {
const newName = Math.floor(Math.random() * 100000);
const input = evt.currentTarget;
const previousFile = input.files[0];
const newFile = new File([previousFile], newName);
// hack to update the selected file
const dT = new DataTransfer();
dT.items.add(newFile);
input.files = dT.files;
console.log('Selected file: ' + input.files.item(0).name);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id='FileID' class='class1' type='file' name='Images' value='' />
However since this part is still mainly an hack, I can't really recommend its use.
So if you don't need to show the updated value in the native input, don't do it. Simply update a custom UI, and use a FormData to upload to your server. The last param of FormData#append(blob, fieldname, filename) will set the filename sent by the browser in the form-data request:
const form = new FormData();
const file = new File(["some data"], "originalname.txt");
form.append("fileField", file, Math.floor(Math.random() * 100000));
console.log("original file's name: ", file.name);
new Response(form).text()
.then((content) => console.log("formdata content: ", content));
So you should not need the aforementioned hacks at all.
For anyone ending here trying to get rid of the file's name, try converting it to base64. this way it won't have the name attached to it and you could upload it how you want. I will leave a code example using reactJS for this.
1: Here is the input file type calling the onChange event with our function:
<input onChange={this.handleBackgroundImagePreview} type="file" accept="image/png,image/gif,image/jpeg"></input>
2: Then convert that image to base64
handleBackgroundImagePreview = (e) =>{
// Retrieves the selected Image or file
const file = e.target.files[0]
//Calling async file reader with a callback
let fileBase64 = '';
this.getBase64(file, (result) => {
fileBase64 = result;
console.log(fileBase64)
//In here you could upload to the server the base 64 data as you want
});
}
getBase64(file, cb) {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
cb(reader.result)
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
}
using react js I need multiple image upload with preview I tried with below code is not working it showing me error in console
Uncaught DOMException: Failed to set the 'value' property on
'HTMLInputElement': This input element accepts a filename, which may
only be programmatically set to the empty string.
uploadImage(e){
var numFiles = e.target.files.length;
for (var i = 0, numFiles = e.target.files.length; i < numFiles; i++){
var file = e.target.files[i];
if(!file.type.match('image'))
continue;
var reader = new FileReader();
reader.onload = function(e) {
setOfImages.push({
fileName:file.name,
image:e.target.result.split(',')[1]
});
for(var j = 0; j<setOfImages.length; j++) {
$('.placeholder-blk').prepend('<div class="image-placeholder"><img src="data:image/jpeg;base64,'+ setOfImages[j].image +'" /></div>');
}
console.log(setOfImages);
}
reader.readAsDataURL(file);
}
}
<input type="file" name="image-uploder" id="image-uploder" className="file-loader" onChange={this.uploadImage.bind(this)} multiple />
Did you try adding the value to the state and populate the name from the state.
Something like
<input type="file" name={this.state.setOfImages} id="image-uploder" className="file-loader" onChange={this.uploadImage.bind(this)} multiple />
and inside your function populate the state.
this.setState({setOfImages: JSON.stringify(setOfImages)})
something like this.
export class Demo extends React.Component{
constructor(props){
super(props)
this.state = {
setOfImages : []
}
}
setOfImages(event){
event.preventDefault();
this.setState({
setOfImages: ["hello", "hi"]
})
}
render(){
return (
<div>
<input value={this.state.setOfImages}/>
<button onClick={this.setOfImages.bind(this)}/>
</div>
)
}
}
Now first the input will be populated with empty array . When you click the button the state will change by setting the setOfImages = ["hello", "hi"] and making the input value set to those values.
This makes no sense $('.placeholder-blk').remove(); then subsequently try to prepend to that? It's gone.
And here only the first file?
var file = e.target.files[0];
Did you mean to process the files
var numFiles = e.target.files.length;
for (var i = 0, numFiles = e.target.files.length; i < numFiles; i++)
{ var file = e.target.files[i]; .. }
Ref here how to do it raw: developer.mozilla.org/en-US/docs/
I have <input type="file" id="basicUploadFile" multiple="multiple"> and I want to get all file names inside this input. I've seen some example, but it gets only name of first file.
$ ('#basicUploadFile').live ('change', function () {
alert($ ('#basicUploadFile').val());
});
How can I do this? Thanks.
var files = $('#basicUploadFile').prop("files")
files will be a FileList object.
var names = $.map(files, function(val) { return val.name; });
Now names is an array of strings (file names)
FileAPI reference
files property reference
jsFiddle Demo
You can still access the files as a FileList collection without the need for over-using jQuery. I've created a quick jsFiddle demonstrating how to get the information out of the input using the FileList and File objects. Here is a snippet:
$('#basicUploadFile').live('change', function ()
{
for (var i = 0; i < this.files.length; i++)
{
alert(this.files[i].name);
alert(this.files.item(i).name); // alternatively
}
});
I used this to show in console all files name:
var input_file = $("#input_file");
input_file.on("change", function () {
var files = input_file.prop("files")
var names = $.map(files, function (val) { return val.name; });
$.each(names, function (i, name) {
console.log(name);
});
});
<input name="selectAttachment" id="selectAttachment" type="file" multiple="multiple">
<button class="btn btn-default" onclick="uploadAttachment()" type="submit">Upload</button>
function uploadAttachment() {
debugger;
var files = $('#selectAttachment').prop('files');
var names = $.map(files, function (val) { return val.name; });
}
you can extend the prototype of File Object (for example File.prototype.toJSON), and you can access the FileList of <input ..>:
<input id="myFile" type="file">
var file = document.getElementById('fileItem').files[0];
For more information check this documentation:
https://developer.mozilla.org/en-US/docs/Web/API/FileList#Using_the_file_list
check this simple example:
File.prototype.toJSON = function() {
return {
'lastModified' : this.lastModified,
'lastModifiedDate' : this.lastModifiedDate,
'name' : this.name,
'size' : this.size,
'type' : this.type
};
}
function getFiles() {
var files = document.getElementById('myFiles').files;
document.getElementById('result').innerHTML = '<h1>result</h1>'
+ JSON.stringify(files);
}
<input id="myFiles" type="file" multiple onchange="getFiles()" />
<pre id='result'></pre>
Good Luck!