I'm trying to upload a file with the format of .csv/.xls/.xlsx and then read the file contents.
For example the following file
would output:
name,age,key
Mark,25,1
Jones,30,2
This is what I've implemented so far using react-file-reader and base-62 but it only works for the .csv files:
onFileUpload(file) {
var decodedData = base64.decode(file.base64);
}
<ReactFileReader fileTypes={[".csv",".xls", ".xlsx"]} base64={true} multipleFiles={false} handleFiles={this.onFileUpload}>
<button className='btn'>Upload</button>
</ReactFileReader>
Is there any way I can get the content of .xls and .xlsx files using the same way as I did for .csv files? Or maybe another module that does this...
I added the code as bellow,
Select Excel File
<ReactFileReader handleFiles={this.handleFiles} fileTypes={[".xls", ".xlsx", ".csv"]} base64={true}>
<button className='btn btn-warning btn-sm'>Select File</button>
{ this.state.isFileLoaded ? <label>File Loaded</label>
: <label>File Not Selected</label> }
</ReactFileReader>
<span id="errprojectLogoUrl" className="text text-danger"></span>
then I wrote the handleFiles as following and it was successful for me,
handleFiles = files => {
this.showLoading();
const currentMsgModal = {
...this.state.messageModal
};
currentMsgModal["isModalHidden"] = true;
let jsonBase64 = files.base64;
let index = jsonBase64.indexOf(',');
let encodedString = jsonBase64.substr(index + 1);
let fileName = files.fileList[0].name;
let formatString = /[^.]*$/.exec(fileName)[0];
let isCSVFile = formatString.includes('csv');
let isXLSFile = formatString.includes('xls');
let isXLSXFile = formatString.includes('xlsx');
if (isCSVFile || isXLSFile || isXLSXFile)
{
this.setState({
inputFileBaseString: encodedString,
isFileLoaded: true,
messageModal: currentMsgModal
});
}
else
{
currentMsgModal["messageType"] = "Error"
currentMsgModal["messageDescription"] = "File Type Not Supported"
currentMsgModal["isModalHidden"] = false;
this.setState({
messageModal: currentMsgModal
});
}
this.hideLoading();
}
Related
I am working on a django app in which the html code called tool.hmtl along with the javascript code called myscripts.js let the user upload the folder and then do some processing on that data. Relevant section of tool.hmtl is given as follows.
<main class="tool mg-t-900">
<div id="folderUploadDiv">
<h1 class="tool__heading | text-center text-capitalize">
Upload your folder here
</h1>
<label
for="folder"
class="tool__upload | flex flex-center flex-column mg-t-500 text-center"
>
<i class="ri-upload-cloud-line tool__icon"></i>
<p class="tool__txt text-capitalize">Browse folder to upload</p>
</label>
<input type="file" id="folder" webkitdirectory multiple />
.............some code......
<script src="{% static 'myscripts.js' %}"></script>
<script src="{% static 'app.js' %}"></script>
<script>
const fileInput = document.querySelector("#folder");
const loder = document.querySelector(".loder");
const toggleLoder = function () {
loder.classList.add("active");
setTimeout(() => {
loder.classList.remove("active");
}, 30000);
startTypingAnimation();
};
fileInput.addEventListener("change", toggleLoder);
function startTypingAnimation() {
new TypeIt("#loder-text", {
strings: "Your file is being prepared...",
speed: 75,
loop: true,
}).go();
}
</script>
<script>
setTimeout(function () {
location.reload();
}, 300000); // refresh every 5 minutes (300000 milliseconds)
</script>
</body>
</html>
{% endblock %}
and relevant section of myscripts.js is as under.
// const axios = require('axios');
$("#folderUploadDiv").show();
$("#selectorDiv").hide();
username = "";
contentType = "";
var dataToSend = []
var flag=1
document.getElementById("folder").addEventListener("change", function(event) {
var output = document.querySelector("ul");
var files = event.target.files;
var jsonFiles =0;
var rightOrderFiles = [];
for (var i=0; i<files.length; i++) {
var item = document.createElement("li");
var innerFiles = files[i].webkitRelativePath.split("/");
if(innerFiles.length ===4){
jsonFiles++;
rightOrderFiles.push(files[i].webkitRelativePath)
var reader = new FileReader();
reader.onload = onReaderLoad;
reader.readAsText(files[i]);
}
// console.log("file path : ", files[i].webkitRelativePath);
item.innerHTML = files[i].webkitRelativePath;
output.appendChild(item);
};
}, false);
In this code snippets (both HTML and Javascript), we can see that user uploads the folder and then some processing is done in Javascript.
My question is, how can I change the code both in tool.hmtl along with the javascript code myscripts.js such that the user uploads a zip file and a folder is extracted from that zip file rather than user uploading the folder itself. Everything else remain the same, the only change needed is let the user upload zip file instead of the folder directly and the folder is then extracted from the zip file.
To change the code to extract a folder from a zip file, you need to make the following changes in both tool.html and myscripts.js:
1- In tool.html, change the type of the file input to "file" instead of "folder".
<input type="file" id="folder" />
2- In myscripts.js, use a library such as jszip.js to extract the contents of the uploaded zip file. You can add the library to your project by including the following line in the head of tool.html:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.2.2/jszip.min.js"></script>
3- Replace the event listener for the file input with the following code:
document.getElementById("folder").addEventListener("change", function(event) {
var output = document.querySelector("ul");
var file = event.target.files[0];
var reader = new FileReader();
reader.onload = function (e) {
var zip = new JSZip();
zip.loadAsync(e.target.result)
.then(function (zip) {
var rightOrderFiles = [];
var jsonFiles = 0;
zip.forEach(function (relativePath, file) {
if (relativePath.split("/").length === 4) {
jsonFiles++;
rightOrderFiles.push(relativePath);
file.async("text").then(function (content) {
var item = document.createElement("li");
item.innerHTML = relativePath;
output.appendChild(item);
});
}
});
});
};
reader.readAsArrayBuffer(file);
}, false);
This code uses JSZip to load the contents of the uploaded zip file, extract the files and process them in the same manner as before.
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.
I have a form to upload pdf files to firebase I have also set the file input control to accept=" application/pdf " but it always saves the file with application/octet-stream and can't view it. could anyone please help me with any suggestion out there?
Here is my form:
<form [formGroup]="formTemplate" (submit)="onSubmit(formTemplate.value)">
<div class="form-group">
<h4>Please choose a file for upload</h4>
<input type="file" class="form-control"
accept="application/vnd.cups-pdf, application/pdf "
formControlName="selectedFile"
(change)="previewFile($event)">
<p>Please choose a file to upload <span class="text-warning">(pdfs,
docs, or ppts)</span> </p>
<div class="text-danger" *ngIf="isSubmitted &&
formControls.selectedFile.errors?.required">
A file is required</div>
</div>
Here is UploadComponent.ts:
previewFile(event:any){
if(event.target.files && event.target.files[0]){
const reader = new FileReader();
reader.onload = (e:any) => this.imSrc = e.target.result;
reader.readAsDataURL(event.target.files[0]);
this.selectedImage = event.target.files[0];
// console.log(this.selectedImage.name)
this.fileName = this.selectedImage.name;
// console.log(this.fileName);
}
else
this.imSrc = this.defaultImage;
this.selectedImage = null;
};
onSubmit(formValue) {
this.isSubmitted = true;
if(this.formTemplate.valid){
var filePath = `${formValue.category}/${this.fileName.split('.').slice(0,-1).join('.')}_${new Date().getTime()}`;
const fileRef = this.storage.ref(filePath);
this.storage.upload(filePath, this.selectedImage)
.snapshotChanges().pipe(finalize(() =>{
fileRef.getDownloadURL().subscribe((url) =>{
formValue['selectedFile'] = url;
this.service.saveResourceDetails(formValue);
this.resetForm();
})
})).subscribe();
}
}
I have a file upload application which once a file has been selected status will appear saying the name of the file. What I am having an issue with is adjusting the case where there are more than one files being uploaded.
Originally, a count would be given - if you upload three files, '3' would appear. I am attempting to adjust this so that the three file names are displayed. I took the code getting the single file name to show fileName = e.target.value.split('\\').pop(); and tried adding it to the condition is more than one:
if (this.files && this.files.length > 1) {
//fileName = (this.getAttribute('data-multiple-caption') || '').replace('{count}', this.files.length);
//fileName = e.target.value.split('\\').pop();
fileName = e.target.value.split('\\').pop();
console.log('Here is it ' + fileName);
//$('#fileName').html(fileName);
}
What I get is a single file name outputted. I can't figure out how to get the file name list in an array to output.
Does anyone see what I need to adjust?
var inputs = document.querySelectorAll('.inputfile');
Array.prototype.forEach.call(inputs, function(input) {
var label = input.nextElementSibling,
labelVal = label.innerHTML;
if (this.files && this.files.length > 1) {
//fileName = (this.getAttribute('data-multiple-caption') || '').replace('{count}', this.files.length);
//fileName = e.target.value.split('\\').pop();
fileName = e.target.value.split('\\').pop();
console.log('Here is it ' + fileName);
//$('#fileName').html(fileName);
} else {
fileName = e.target.value.split('\\').pop();
console.log("I am running");
}
if (fileName) {
//label.querySelector('span').innerHTML = fileName;
//label.querySelector('span').innerHTML = fileName;
$('#fileName').html(fileName);
$('#fileStatus').text('File attached!');
} else {
label.innerHTML = labelVal;
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="file" name="uploadedFile" class="inputfile" id="uploadedFileTest" data-multiple-caption="{count} files selected" multiple>
<label for="uploadedFileTest" id="uploadFileTest"><img class="total-center" src=""></label>
<p id="fileStatus"></p>
<p id="fileName"></p>
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/