How to use input type file in angular material
Asked Answered
C

11

71

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.

Cabalist answered 3/10, 2018 at 7:38 Comment(2)
Possible duplicate: #31867694Pippas
Yes, Possible but i want like this format <mat-form-field> <input matInput type="file" placeholder="Choose File"> </mat-form-field>Cabalist
H
51

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://mcmap.net/q/278932/-how-to-use-input-type-file-in-angular-material

Hanshansard answered 3/10, 2018 at 8:16 Comment(0)
L
123

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

Lest answered 29/11, 2018 at 19:42 Comment(4)
Wouldn't it be better using the Angular ay instead of query selector ? Like @ViewChild ?Dulles
I think it will better to add $event in onFileSelected($event) function, so you don't required id="file"in input.Careerist
This solution can be simplified a bit. See stackoverflow.com/a/72047999Tattered
You could also pass the file list directly to the method on change by using the template reference (change)="onFileSelected(fileInput.files)"Gonyea
H
51

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://mcmap.net/q/278932/-how-to-use-input-type-file-in-angular-material

Hanshansard answered 3/10, 2018 at 8:16 Comment(0)
T
17

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

Tattered answered 28/4, 2022 at 17:32 Comment(0)
A
8

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

It is very Angular Material Compliant.

enter image description here

Aventine answered 26/3, 2020 at 22:16 Comment(0)
C
5

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>
Coincidental answered 25/6, 2021 at 12:16 Comment(0)
D
3

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. *If you click to input then you can open directly the file dialog.

Dunaj answered 23/8, 2022 at 4:20 Comment(0)
T
1

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;
}
Transpire answered 6/3, 2023 at 15:35 Comment(0)
M
1

It's funny, but in my case it worked with attr binding [attr.type]="'file'" instead of setting attribute directly type="file"

Monsoon answered 31/5, 2023 at 17:25 Comment(1)
Works, but the styles are all messed upLheureux
C
0

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();
}
Cryogenics answered 29/10, 2020 at 19:51 Comment(0)
T
0

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>
 
Toxicosis answered 29/9, 2021 at 11:2 Comment(0)
P
0

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
  });
};
Pyotr answered 11/2 at 17:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.