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.
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.
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:
ngx-material-file-input: Link to repository
Supported features:
ngx-mat-file-input
component, to use inside Angular Material mat-form-field
FileValidator
with maxContentSize
, to limit the file sizeByteFormatPipe
to format the file size in a human-readable formatUpdate
See the answer here if you just need a workaround without external library https://mcmap.net/q/278932/-how-to-use-input-type-file-in-angular-material
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
$event
in onFileSelected($event)
function, so you don't required id="file"
in input. –
Careerist (change)="onFileSelected(fileInput.files)"
–
Gonyea 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:
ngx-material-file-input: Link to repository
Supported features:
ngx-mat-file-input
component, to use inside Angular Material mat-form-field
FileValidator
with maxContentSize
, to limit the file sizeByteFormatPipe
to format the file size in a human-readable formatUpdate
See the answer here if you just need a workaround without external library https://mcmap.net/q/278932/-how-to-use-input-type-file-in-angular-material
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:
I would suggest you to checkout @angular-material-components/file-input.
It is very Angular Material Compliant.
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>
You can also use this method (with Tailwind CSS). There are two inputs here. The first one is transparent file input. The file input is the front side by z-index. The back side has another input (matInput).
<mat-form-field class="w-full">
<input
type="file"
class="absolute top-0 z-10 h-full w-full cursor-pointer opacity-0"
accept=".jpeg,.jpg,.png"
/>
<mat-label>{{ matLabel }}</mat-label>
<input
matInput
cdkFocusInitial
class="z-0"
/>
<mat-icon matSuffix class="mr-2">cloud_upload</mat-icon>
<mat-hint class="mat-form-field-hint-end"
>JPEG / JPG / PNG</mat-hint
>
</mat-form-field>
*If you click to input then you can open directly the file dialog.
I found a quick and easy way to solve this problem.
I make the input for the file look like an input for the text.
HTML:
<mat-form-field>
<mat-label>Select file</mat-label>
<input matInput readonly type="text" id="fakeFileInput" (click)="hiddenInput.click()">
<input hidden type="file" accept=".csv" #hiddenInput (change)="GetFileOnLoad($event)">
<mat-icon matSuffix>folder_open</mat-icon>
</mat-form-field>
TypeScript:
public GetFileOnLoad(event: any) {
var file = event.target.files[0];
var element = document.getElementById("fakeFileInput") as HTMLInputElement | null;
if(element != null) {
element.value = file?.name;
}
It's funny, but in my case it worked with attr binding [attr.type]="'file'"
instead of setting attribute directly type="file"
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();
}
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>
There is a more modern API Blob.text
which can do this in a simpler way:
<button mat-button (click)="fileInput.click()">Choose File</button>
<input type="file" #fileInput hidden (change)="onFileSelected($event)">
onFileSelected = (event: Event & { target: HTMLInputElement }) => {
event.target.files?.[0]?.text().then(text => {
// use text
});
};
© 2022 - 2024 — McMap. All rights reserved.