I have a file upload control in my angular app where user could upload any type of file except a few ones .exe, .sql etc
<input type="file" id="file" #file (change)="fileUploadHandler($event)" multiple>
fileupload.component.ts
fileUploadHandler(event: Event) {
const inputElement = event.target as HTMLInputElement;
if (inputElement.files && inputElement.files?.length) {
_each(inputElement.files, (_file) => {
const fileSize = _file.size;
if (fileSize < this.MAX_DOC_SIZE) {
const fileName = _file.name?.trim();
const doc = new Document();
doc.name = fileName;
doc.extension = fileName.slice(fileName.lastIndexOf('.') + 1);
doc.size = fileSize;
this.docs.push(doc);
}
});
}}
This list the files in UI as below
Now what I need is that when user click on a file, that file should open in a new tab
how can I do this?
On googling I see suggestions to use FileReader & gave a try
_each(inputElement.files, (_file) => {
const reader = new FileReader();
const data = reader.readAsDataURL(_file);
console.log(data) // nothing is printed on console
Please suggest. Thanks!
You have to enhance the code a little bit (as #mav-raj also stated). In Angular you can use the following:
_each(inputElement.files, (_file) => {
const reader = new FileReader();
reader.onloadend = ((result) => {
console.log(result) // now something will be printed!
});
reader.readAsDataURL(_file);
})
To upload I file in Angular, I am doing this:
<input type="file" (change)="onFileSelected($event.target.files)"/>
<button (click)="onStartUpload()"</button>
public onFileSelected(files: File[]) {
this.file = files[0];
}
public onStartUpload() {
// Upload the file
}
This works perfectly. But when I select a file, then change its content and save it, and then upload it, my backend response is this:
Unexpected end of Stream, the content may have already been read by
another component.
This only happens with Firefox. It works fine in Chrome.
Update: With Chrome's latest update, it does not send the request
anymore.
How can I check if the file has been changed after I selected it in the browser?
If you use an instance of the FileReader object, you can take advantage of the fact that it wont load a file that's been altered after having been selected. In order to upload the file successfully, it must remain the same as it was when it was chosen.
Here's a short example that will demonstrate. Tested on the current iteration of Chrome x64 under windows.
window.addEventListener('load', onLoaded, false);
function onLoaded(evt) {
document.querySelector('button').addEventListener('click', onBtnClicked, false);
}
function onBtnClicked(evt) {
let fileToUpload = document.querySelector('input').files[0];
const fileReader = new FileReader();
fileReader.onload = fileLoaded;
fileReader.onerror = fileError;
fileReader.readAsText(fileToUpload);
// fileReader.readAsArrayBuffer(fileToUpload);
// fileReader.readAsBinaryString(fileToUpload);
// fileReader.readAsDataURL(fileToUpload);
function fileLoaded(evt) {
let fileToUpload = evt.target.result;
}
function fileError(evt) {
console.log('Error loading file');
console.log(evt.target.error);
}
}
<input type='file' /><br>
<button>Go</button>
I am new to Jhipster and trying to create a basic app that will allow a user to upload a CSV file and then view the contents in an entity.
I am trying to figure out a way to populate a second entity with the data contained in a CSV blob that will be uploaded by the user. I have created an entity that allows the user to upload a CSV file and store it in the database as a BLOB, and I have also created a service with the intention of populating a second entity with records based on the contents of the CSV file that was uploaded.
How would I go about this? I have used OpenCSV in the past to read CSV files and populate MySQL tables via their filepath, but I am unfamiliar with accessing CSV files that are stored in the database as a BLOB.
I implemented same use case using supercsv but I don't store the csv in blob: in service I parse the DTO from controller and stores resulting entities, in the blob I store the errors if any. It's a bit abusive but it works well and the entity to create the other one is just a way to record how upload went, this way I can reuse the UI generated by JHipster without any change.
1.in html:
</td>
<td style="padding: 5px;">
<input type="button"
name="Reset"
id="txtFileReset"
class="btn btn-primary"
(click)="csvReset()"
value="Reset"/>
<input type="button"
name="Reset"
id="txtFileSave"
class="btn btn-primary"
(click)="csvSave()"
value="Save CSV To DB"/>
</td>
2.in ts:
csvRecords = [];
fileChangeListener($event): void {
const text = [];
const target = $event.target || $event.srcElement;
const files = target.files;
if (Constants.validateHeaderAndRecordLengthFlag) {
if (!this.fileUtil.isCSVFile(files[0])) {
alert('Please import valid .csv file.');
this.csvReset();
}
}
const input = $event.target;
const reader = new FileReader();
reader.readAsText(input.files[0]);
reader.onload = data => {
const csvData = reader.result;
const csvRecordsArray = csvData.split(/\r\n|\n/);
let headerLength = -1;
if (Constants.isHeaderPresentFlag) {
const headersRow = this.fileUtil.getHeaderArray(csvRecordsArray, Constants.tokenDelimeter);
headerLength = headersRow.length;
}
this.csvRecords = this.fileUtil.getDataRecordsArrayFromCSVFile(
csvRecordsArray,
headerLength,
Constants.validateHeaderAndRecordLengthFlag,
Constants.tokenDelimeter
);
if (this.csvRecords === null) {
// If control reached here it means csv file contains error, reset file.
this.csvReset();
}
};
reader.onerror = function() {
alert('Unable to read ' + input.files[0]);
};
}
csvReset() {
this.elementRef.nativeElement.querySelector('#txtFileUpload').value = '';
this.csvRecords = [];
}
csvSave() {
this.ipInfo = new IpInfoSdmSuffix();
for (let i = 1; i < this.csvRecords.length; i++) {
this.ipInfo.name = this.csvRecords[i][0];
this.ipInfo.addressStart = this.csvRecords[i][1];
this.ipInfo.addressEnd = this.csvRecords[i][2];
this.ipInfo.validType = this.csvRecords[i][3];
this.subscribeToSaveResponse(this.ipInfoService.create(this.ipInfo));
}
}
private subscribeToSaveResponse(result: Observable<HttpResponse<IIpInfoSdmSuffix>>) {
result.subscribe((res: HttpResponse<IIpInfoSdmSuffix>) => this.onSaveSuccess(), (res: HttpErrorResponse) => this.onSaveError());
}
private onSaveSuccess() {
this.isSaving = false;
this.isCsvSaved = false;
// this.previousState();
this.clear();
}
private onSaveError() {
this.isSaving = false;
this.isCsvSaved = false;
}
I have made me a simple file field:
<input type="file" name="pictures_array[]" multiple accept="image/*" id="page_pictures_array" />
and some HTML5 File API code to list the files:
$('.page-form #page_pictures_array').change(function(evt) {
var file, files, reader, _i, _len;
files = evt.target.files;
console.log(files);
$('#file-list').empty();
for (_i = 0, _len = files.length; _i < _len; _i++) {
file = files[_i];
reader = new window.FileReader;
reader.onload = (function(file) {
return function(e) {
var src;
src = e.target.result;
return $("<li>" + file.name + " - " + file.size + " bytes</li>").prepend($('<img/>', {
src: src,
"class": 'thumb'
})).appendTo($('#file-list'));
};
})(file);
reader.readAsDataURL(file);
}
});
(cf. here)
However, since I expect my users to be very stupid indeed, I am sure they will choose one file, then click on the upload field another time to choose the next. However, the list of the <input type="file"> is reset each time with the newly chosen images.
How can I make sure the new files are appended to the <input>'s array so I don't get flooded with angry user comments?
I'm also looking for an answer to this, I think others already do that.
But if you look at the filelist W3 reference http://www.w3.org/TR/FileAPI/#dfn-filelist it says that its readonly....
Edit: It's a big code now, with some improvements, that make the copy/paste difficult. But I started to create one variable that saves all the tmp files.
var tmp_files = new Array();
Then when I add a new file I push the file to that array like this
tmp_files.push(file);
After all the insertions/removals (I have another var to save the deletions) when the user clicks to send the files I have this code that makes the formdata with the files I want
var data = new FormData(); var count = 0;
$.each(tmp_files, function(i, file){
if(del_files.indexOf(file.name)== -1){
data.append(count, file);
count++;
}
});
Then I just send the var data thru ajax and save them.
You can get them using $data = $_FILES;
Hope this helps you.
I would like to simply limit the size of a file that a user can upload.
I thought maxlength = 20000 = 20k but that doesn't seem to work at all.
I am running on Rails, not PHP, but was thinking it'd be much simpler to do it client side in the HTML/CSS, or as a last resort using jQuery. This is so basic though that there must be some HTML tag I am missing or not aware of.
Looking to support IE7+, Chrome, FF3.6+. I suppose I could get away with just supporting IE8+ if necessary.
Thanks.
var uploadField = document.getElementById("file");
uploadField.onchange = function() {
if(this.files[0].size > 2097152){
alert("File is too big!");
this.value = "";
};
};
This example should work fine. I set it up for roughly 2MB, 1MB in Bytes is 1,048,576 so you can multiply it by the limit you need.
Here is the jsfiddle example for more clearence:
https://jsfiddle.net/7bjfr/808/
This is completely possible. Use Javascript.
I use jQuery to select the input element. I have it set up with an onChange event.
$("#aFile_upload").on("change", function (e) {
var count=1;
var files = e.currentTarget.files; // puts all files into an array
// call them as such; files[0].size will get you the file size of the 0th file
for (var x in files) {
var filesize = ((files[x].size/1024)/1024).toFixed(4); // MB
if (files[x].name != "item" && typeof files[x].name != "undefined" && filesize <= 10) {
if (count > 1) {
approvedHTML += ", "+files[x].name;
}
else {
approvedHTML += files[x].name;
}
count++;
}
}
$("#approvedFiles").val(approvedHTML);
});
The code above saves all the file names that I deem worthy of persisting to the submission page before the submission actually happens. I add the "approved" files to an input element's val using jQuery so a form submit will send the names of the files I want to save. All the files will be submitted, however, now on the server-side, we do have to filter these out. I haven't written any code for that yet but use your imagination. I assume one can accomplish this by a for loop and matching the names sent over from the input field and matching them to the $_FILES (PHP Superglobal, sorry I don't know ruby file variable) variable.
My point is you can do checks for files before submission. I do this and then output it to the user before he/she submits the form, to let them know what they are uploading to my site. Anything that doesn't meet the criteria does not get displayed back to the user and therefore they should know, that the files that are too large won't be saved. This should work on all browsers because I'm not using the FormData object.
You can't do it client-side. You'll have to do it on the server.
Edit: This answer is outdated!
When I originally answered this question in 2011, HTML File API was nothing but a draft. It is now supported on all major browsers.
I'd provide an update with solution, but #mark.inman.winning has already answered better than I could.
Keep in mind that even if it's now possible to validate on the client, you should still validate it on the server, though. All client side validations can be bypassed.
const input = document.getElementById('input')
input.addEventListener('change', (event) => {
const target = event.target
if (target.files && target.files[0]) {
/*Maximum allowed size in bytes
5MB Example
Change first operand(multiplier) for your needs*/
const maxAllowedSize = 5 * 1024 * 1024;
if (target.files[0].size > maxAllowedSize) {
// Here you can ask your users to load correct file
target.value = ''
}
}
})
<input type="file" id="input" />
If you need to validate file type, write in comments below and I'll share my solution.
(Spoiler: accept attribute is not bulletproof solution)
Video file example (HTML + Javascript):
function upload_check()
{
var upl = document.getElementById("file_id");
var max = document.getElementById("max_id").value;
if(upl.files[0].size > max)
{
alert("File too big!");
upl.value = "";
}
};
<form action="some_script" method="post" enctype="multipart/form-data">
<input id="max_id" type="hidden" name="MAX_FILE_SIZE" value="250000000" />
<input onchange="upload_check()" id="file_id" type="file" name="file_name" accept="video/*" />
<input type="submit" value="Upload"/>
</form>
I made a solution using just JavaScript, and it supports multiple files:
const input = document.querySelector("input")
const result = document.querySelector("p")
const maximumSize = 10 * 1024 * 1024 // In MegaBytes
input.addEventListener("change", function(e){
const files = Array.from(this.files)
const approvedFiles = new Array
if(!files.length) return result.innerText = "No selected files"
for(const file of files) if(file.size <= maximumSize) approvedFiles.push(file)
if(approvedFiles.length) result.innerText = `Approved files: ${approvedFiles.map(file => file.name).join(", ")}`
else result.innerText = "No approved files"
})
<input type="file" multiple>
<p>Result</p>
This question was from a long time ago, but maybe this could help someone struggling.
If you are working with forms, the easiest way to do this is by creating a new FormData
with your form. For example:
form.addEventListener("submit", function(e){
e.preventDefault()
const fd = new FormData(this)
for(let key of fd.keys()){
if(fd.get(key).size >= 2000000){
return console.log(`This archive ${fd.get(key).name} is bigger than 2MB.`)
}
else if(fd.get(key).size < 2000000){
console.log(`This archive ${fd.get(key).name} is less than 2MB.`)
}
else{
console.log(key, fd.get(key))
}
}
this.reset()
})
As you can see, you can get the size from an archive submited with a form by typing this:
fd.get(key).size
And the file name is also reachable:
fd.get(key).name
Hope this was helpful!
<script type="text/javascript">
$(document).ready(function () {
var uploadField = document.getElementById("file");
uploadField.onchange = function () {
if (this.files[0].size > 300000) {
this.value = "";
swal({
title: 'File is larger than 300 KB !!',
text: 'Please Select a file smaller than 300 KB',
type: 'error',
timer: 4000,
onOpen: () => {
swal.showLoading()
timerInterval = setInterval(() => {
swal.getContent().querySelector('strong')
.textContent = swal.getTimerLeft()
}, 100)
},
onClose: () => {
clearInterval(timerInterval)
}
}).then((result) => {
if (
// Read more about handling dismissals
result.dismiss === swal.DismissReason.timer
) {
console.log('I was closed by the timer')
}
});
};
};
});
</script>
PHP solution to verify the size in the hosting.
<?php
if ($_FILES['name']['size'] > 16777216) {
?>
<script type="text/javascript">
alert("The file is too big!");
location.href = history.back();
</script>
<?php
die();
}
?>
16777216 Bytes = 16 Megabytes
Convert units: https://convertlive.com/u/convert/megabytes/to/bytes#16
Adapted from https://www.php.net/manual/en/features.file-upload.php