How to use input type file in angular material

AngularAngular MaterialMaterial Design

Angular Problem Overview


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 Solutions


Solution 1 - Angular

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 2 - Angular

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 3 - Angular

I would suggest you to checkout @angular-material-components/file-input.

It is very Angular Material Compliant.

enter image description here

Solution 4 - Angular

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 - Angular

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 - Angular

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 - Angular

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>
 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHariom SinghView Question on Stackoverflow
Solution 1 - AngularJackMorrisseyView Answer on Stackoverflow
Solution 2 - AngularbillyjovView Answer on Stackoverflow
Solution 3 - AngularhqhoView Answer on Stackoverflow
Solution 4 - AngularBrunoEloView Answer on Stackoverflow
Solution 5 - AngularAmplifyView Answer on Stackoverflow
Solution 6 - AngulartonyView Answer on Stackoverflow
Solution 7 - AngularyantrabView Answer on Stackoverflow