'How to use input type file in angular material
How to use input type file in angular material
Hi, I am using angular material for designing. when i go on angular material site there no input type file element. anyone know about this.
Solution 1:[1]
Angular Material does not support yet a workaround for file upload. There are alternative to archieve this. e.g using external libraries.
angular-material-fileupload: link to npm package
Supported features:
- Drag and drop
- common uploads
- progress bar
- file size and more...
ngx-material-file-input: Link to repository
Supported features:
ngx-mat-file-input
component, to use inside Angular Materialmat-form-field
- a
FileValidator
withmaxContentSize
, to limit the file size - a
ByteFormatPipe
to format the file size in a human-readable format - and more small minor features...
Update
See the answer here if you just need a workaround without external library https://stackoverflow.com/a/53546417/6432698
Solution 2:[2]
Here is a workaround if all you want is a nicely displayed file input button.
Html
<button type="button" mat-raised-button (click)="fileInput.click()">Choose File</button>
<input hidden (change)="onFileSelected()" #fileInput type="file" id="file">
Component
onFileSelected() {
const inputNode: any = document.querySelector('#file');
if (typeof (FileReader) !== 'undefined') {
const reader = new FileReader();
reader.onload = (e: any) => {
this.srcResult = e.target.result;
};
reader.readAsArrayBuffer(inputNode.files[0]);
}
}
Inspired by this Angular Material Github Issue comment https://github.com/angular/material2/issues/3262#issuecomment-309000588
Solution 3:[3]
I would suggest you to checkout @angular-material-components/file-input.
It is very Angular Material Compliant.
Solution 4:[4]
Made more sense to just style the default input element of type file using the ::file-selector-button to look like the angular material button. Also, this way accounts for UX which lets the user know that the file to upload has been added to the form by displaying the file name.
P.S. Style was copied from the declarations after inspecting the angular mat-raised-button
input[type="file"]::file-selector-button {
box-shadow: 0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);
background: #ffd740;
box-sizing: border-box;
position: relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: pointer;
outline: none;
border: none;
-webkit-tap-highlight-color: transparent;
display: inline-block;
white-space: nowrap;
text-decoration: none;
vertical-align: baseline;
text-align: center;
margin: 0;
min-width: 64px;
line-height: 36px;
padding: 0 16px;
border-radius: 4px;
overflow: visible;
transform: translate3d(0, 0, 0);
transition: background 400ms cubic-bezier(0.25, 0.8, 0.25, 1), box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
margin: 1rem;
}
/* fallback for older browsers supporting the -webkit prefix */
input[type="file"]::-webkit-file-upload-button {
box-shadow: 0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);
background: #ffd740;
box-sizing: border-box;
position: relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: pointer;
outline: none;
border: none;
-webkit-tap-highlight-color: transparent;
display: inline-block;
white-space: nowrap;
text-decoration: none;
vertical-align: baseline;
text-align: center;
margin: 0;
min-width: 64px;
line-height: 36px;
padding: 0 16px;
border-radius: 4px;
overflow: visible;
transform: translate3d(0, 0, 0);
transition: background 400ms cubic-bezier(0.25, 0.8, 0.25, 1), box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
margin: 1rem;
font-weight: 500;
}
<form>
<label for="fileUpload">Add file</label>
<input type="file" id="fileUpload">
</form>
Solution 5:[5]
Building on @JackMorrissey's answer, I found a more simplified solution:
HTML:
<button type="button" mat-raised-button (click)="fileInput.click()">Choose File</button>
<input hidden (change)="onFileSelected($event)" #fileInput type="file">
<span class="file-name">{{selectedFile?.name}}</span>
TypeScript:
selectedFile: any = null;
onFileSelected(event: any): void {
this.selectedFile = event.target.files[0] ?? null;
}
CSS:
.file-name {
margin-left: 1rem; /* or whatever margin you require */
}
Output:
Solution 6:[6]
If you dont want to use some strange workaround, then just dont place input
into the mat-form-field
. You can place it outside the mat-form-field
but still include the value into the FormGroup
. Check the example
<form [formGroup]="someForm" (ngSubmit)="onSubmit()">
<!--input outside the form-field-->
<input type="file" (Change)="onChange($event)"/>
<mat-form-field>
<!--input inside the form-field-->
<input matInput formControlName="someFCN">
</mat-form-field>
<button mat-raised-button>Submit</button>
</form>
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
someForm: FormGroup;
constructor(private formBuilder: FormBuilder) {}
ngOnInit(): void {
this.someForm = this.formBuilder.group({
someFCN: [{ value:'', disabled: false },Validators.required],
file: { value:'', disabled: false }
});
}
onChange(event: Event) {
/*not sure what you want to do with file, i'll just set
selected file´s name as value, but obviously u can do much more than just get file´s name.*/
this.someForm.controls['file'].setValue(event.target.files[0].name);
}
onSubmit() {
return this.someForm.getRawValue();
}
Solution 7:[7]
Create directive -
import { Directive, ElementRef, EventEmitter, Inject, Output } from '@angular/core';
import { DOCUMENT } from '@angular/common';
@Directive({
selector: '[appFileUpload]'
})
export class FileUploadDirective {
@Output() fileContent: EventEmitter<ArrayBuffer | string> = new EventEmitter();
constructor(private elementRef: ElementRef, @Inject(DOCUMENT) private document: Document) {
this.elementRef.nativeElement.addEventListener('click', () => {
const input = this.document.createElement('input');
input.type = 'file';
input.onchange = ev => {
const file = (ev.target as HTMLInputElement).files?.item(0);
const reader = new FileReader();
reader.onload = e => {
this.fileContent.next(reader.result!);
input.value = '';
};
switch (file?.type) {
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
reader.readAsArrayBuffer(file!);
break;
default:
reader.readAsText(file!);
}
};
input.click();
input.remove();
});
}
}
and then use it like -
<button appFileUpload (fileContent)="uploadDump($event)" mat-menu-item><mat-icon>upload_file</mat-icon></button>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | JackMorrissey |
Solution 3 | hqho |
Solution 4 | BrunoElo |
Solution 5 | |
Solution 6 | tony |
Solution 7 |