'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 Material mat-form-field
  • a FileValidator with maxContentSize, 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.

enter image description here

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:

file select

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