File reader doesn't load first time - VUE.JS [duplicate] - javascript

This question already has answers here:
How to return value from an asynchronous callback function? [duplicate]
(3 answers)
Closed 3 years ago.
I have a problem with a file reader, it load the file never the fist time, and it's like a queue. I mean: it start from the second time I select a file but it upload the first.
Can I solve this?
Here the code.
<v-text-field
v-if="switch1"
label="Upload Fattura"
#click='onPickFile'
v-model='fatturaFileName'
prepend-icon="mdi-paperclip"
></v-text-field>
<input
type="file"
style="display: none"
ref="fileInput"
accept="text/xml"
#change="onFilePicked"
>
onPickFile () {
this.$refs.fileInput.click();
}`
onFilePicked (event) {
if (event) event.preventDefault();
var files = event.target.files[0];
if (files !== undefined) {
this.fatturaFileName = files.name;
// If valid, continue
const fr = new FileReader();
fr.readAsText(files);
fr.addEventListener('load', () => {
this.fatturaUpload = fr.result;
});
} else {
this.fatturaFileName = ''
this.fatturaFileObject = null
}
console.log(this.fatturaUpload);
}

It works fine using the following code :
onFilePicked (event) {
if (event) event.preventDefault();
var fichier = event.target.files[0];
if (fichier != undefined) {
const fr = new FileReader();
fr.readAsDataURL(fichier);
var reader = new FileReader();
let file = fichier;
reader.readAsText(file, "UTF-8");
reader.onload = evt => {
console.log("1",evt.target.result)
};
} else {
console.log("2",fichier)
this.fatturaFileName = ''
this.fatturaFileObject = null
}
console.log("3",this.fatturaUpload);
this.fatturaFileName = '';
this.fatturaFileObject = null;
}
See the Pen
Vuetify Template by boussadjra (#boussadjra)
on CodePen.

Related

Angular Uploading a File with Copy Paste

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.

how to invoke a click event without clicking?

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

Image preview before upload in angular 5

I have this code to show the image preview before uploading it. However I am working with Angular 5 so I have a .ts file instead of a .js one. How can I do the same in Angular 5? I also want to show the image in all browsers.
My HTML:
<input type='file' onchange="readURL(this);"/>
<img id="blah" src="http://placehold.it/180" alt="your image"/>
My CSS:
img {
max-width:180px;
}
input[type=file] {
padding: 10px;
background: #2d2d2d;
}
My JavaScript:
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
document.getElementById('blah').src=e.target.result
};
reader.readAsDataURL(input.files[0]);
}
}
.html
Update event attr and handler param for input.
And you should use data binding for src attribute. Following will apply src if it's not null or undefined or hardcoded url ('http://placehold.it/180')
<input type='file' (change)="readURL($event);" />
<img id="blah" [src]="imageSrc || 'http://placehold.it/180'" alt="your image" />
.ts
In component ts file (class) you should have property imageSrc which be used in view (html) and your function should be a method of that class
...
imageSrc: string;
...
constructor(...) {...}
...
readURL(event: Event): void {
if (event.target.files && event.target.files[0]) {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = e => this.imageSrc = reader.result;
reader.readAsDataURL(file);
}
}
I know I'm late but just ran into this problem for both image and audio. The above solutions worked just fine for images but not so well for audio. I eventually got it all working by using a URL object instead of FileReader object that everyone is using.
something like the following
component.ts file ~
imgSrc = 'assets/path/to/default/image.jpeg'
imgFileSelected(event: any) {
if (event.target.files && event.target.files[0]) {
this.imgSrc = URL.createObjectURL(event.target.files[0]);
}
}
My component.html looks like~
<img [src]="imgSrc | sanitizeUrl"> <!-- using a Custom Pipe -->
Finally I created a custom pipe to rid the console of warnings.
my pipe is as follows~
#Pipe({
name: 'sanitizerUrl'
})
export class SanitizerUrlPipe implements PipeTransform {
constructor (
private sanitize: DomSanitizer
) {}
transform(value: string): SafeUrl {
return this.sanitize.bypassSecurityTrustUrl(value);
}
}
To see how I used this for the audio tag you can check out this link. It's only 2 extra lines of self-explanatory code.
I am using the below code to implement the image preview:
onFileChange(event: any) {
this.userFile = event.target.files[0];
this.imageSelected = this.userFile.name;
if (event.target.files && event.target.files[0]) {
const reader = new FileReader();
reader.onload = (e: any) => {
this.imageSrc = e.target.result;
};
reader.readAsDataURL(event.target.files[0]);
}}
Which works just fine and displays the image preview. The problem I originally faced was that I receeived the below error in the chrome developer tools each time an image preview is generated:
Everything worked fine though, there are no other errors.
If I clicked on the null:1 I was directed to the below:
After some fiddling and troubleshooting, I was able to find the solution which I have included in the edit below.
EDIT: Figured it out. I didn't have the || 'http://placehold.it/180'" included in the [src]=" on my component.html. Guess its a timing issue. Sorted now. no more error.
What about using #HostListner, since Angular doesn’t come with a built-in value accessor for file input.
#HostListener('change', ['$event.target.files'])
emitFiles( event: FileList ) {
const file = event && event.item(0);
this.onChange(file);
const reader = new FileReader();
reader.readAsDataURL(file); // toBase64
reader.onload = () => {
this.imageURL = reader.result as string; // base64 Image src
};
Then in the HTML, you may use something like:
<picture >
<source media='(min-width:0px)' [srcset]="imageURL">
<img src="" [alt]="Your photo">
</picture>
Kindly change like --> this.url = event.target.result;
readURL(event:any) {
if (event.target.files && event.target.files[0]) {
var reader = new FileReader();
reader.onload = (event:any) = > {
this.url = event.target.result;
}
reader.readAsDataURL(event.target.files[0]);
}
}
You might just need to change your javascript function to typescript as below.
readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = (e:any) => {
(<HTMLImageElement>document.getElementById('blah')).src=e.target.result
//assuming element with id blah will always be an ImageElement
};
reader.readAsDataURL(input.files[0]);
}
}
That should be it.
Update
You can also define a property and bind it to image src and change its value accordingly as below:
In your .ts file before constructor, define a property as url and set its default value to http://placehold.it/180.
url: string = 'http://placehold.it/180';
You can update this property within reader.onload as below:
readURL(event:any) {
if (event.target.files && event.target.files[0]) {
var reader = new FileReader();
reader.onload = (event:any) => {
this.url = event.target.result;
}
reader.readAsDataURL(event.target.files[0]);
}
}
Your html will now look like below:
<input type='file' (change)="readURL(this);" />
<img id="blah" [src]="url" alt="your image" />
to preview the chosen image before uploading this code will help you it,s easy. it,s preview only image if anything else then it,s will give you error
this code is for component.ts
public imagePath;
imgURL: any;
public message: string;
preview(files) {
if (files.length === 0)
return;
var mimeType = files[0].type;
if (mimeType.match(/image\/*/) == null) {
this.message = "Only images are supported.";
return;
}
var reader = new FileReader();
this.imagePath = files;
reader.readAsDataURL(files[0]);
reader.onload = (_event) => {
this.imgURL = reader.result;
}
}
and these lines of code in component view
<span style="color:red;" *ngIf="message">{{message}}</span>
<input #file type="file" accept='image/*' (change)="preview(file.files)" />
<img [src]="imgURL" height="200" *ngIf="imgURL">
First we input the image by upload in choose file (imagedisplay.component.html) :
<input #Image type="file" (change)="handleFileInput($event.target.files)"/>
<img width="100%" *ngIf="imageUrl" [src]="imageUrl" class="image">
Then we use the function for reading and displaying further this is done so (imagedisplay.component.ts):
export class ImageDisplayComponent {
name = 'Angular';
fileToUpload: any;
imageUrl: any;
handleFileInput(file: FileList) {
this.fileToUpload = file.item(0);
//Show image preview
let reader = new FileReader();
reader.onload = (event: any) => {
this.imageUrl = event.target.result;
}
reader.readAsDataURL(this.fileToUpload);
}
}
For those who followed the accepted answer and had type 'string | ArrayBuffer' is not assignable to type 'string'; you need to add as string when affecting render result to your image src as the following
readURL(event: Event): void {
...
reader.onload = e => this.imageSrc = reader.result as string;
...
}
}

Read input field files when seperate button is clicked

With the following input field, the user submits one or multiple HTML files.
<input type="file" id="inputfield" accept="text/html" multiple/>
<div id="get-files">Get Files</div>
When get-files is clicked, how can I get the content of each file on the input field and mess with each file content using the fileReader API?
I tried the following but receive no errors or content.
$("#get-files").on("click", function() { getFilesContent(); });
function getFilesContent() {
var pages = $("#inputfield")[0].files;
// get files data
for (var i = 0; i < pages.length; i++) {
var reader = new FileReader();
reader.onload = (function() {
return function(e) {
console.log($("#inputfield")[0].result);
}
});
reader.readAsText(pages[i]);
}
}
Try this instead
function getFilesContent() {
var pages = $("#inputfield")[0].files;
for (let i = 0; i < pages.length; i++) {
let reader = new FileReader();
reader.onload = function() {
console.log(reader.result);
}
reader.readAsText(pages[i]);
}
}
reader.result contains your HTML data.

Insert a photo to <img> by opening <input type = "file">

Tell me, please, how can a photo be inserted to <img>, when I open
<input type = "file"> and choose any file ?
How can I use JS / JQuery ?
Use 'FileReader' object:
$("#yourinput").change(function () {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function (e) {
$("#yourimg").attr("src", e.target.result);
}
reader.readAsDataURL(file);
});

Categories