avermaet
avermaet

Reputation: 1593

Angular binding to selection of file input field?

I have a simple upload form and would like to bind the displayed filename to the value of the file input field <input type="file">, but for some reason it always shows some virtual filepath. How can the binding be improved to not have this behavior(only filename, like selected.files[0].name)?

Ideally the selected filename would be shown in the label for #selected right after the OS filechooser finishes. Another approach of mine is included in the comments (*ngIf), but it doesn't work either.

<form>
    <div class="justify-content-center">
        <div class="input-group mb-3">
      <div class="input-group-prepend">
        <span class="input-group-text">Select image</span>
      </div>
            <div class="custom-file">
                <input type="file" accept="image/*" class="custom-file-input" id="selected" #selected (click)="message=''" >
        <label class="custom-file-label" for="selected">{{ selected.value }}</label>
<!--
        <div *ngIf="selected.files[0].name; then showFilename else showDefaultMsg"></div>
        <ng-template #showFilename>
        <label class="custom-file-label" for="selected">{{ selected.files[0].name }}</label>
        </ng-template>
        <ng-template #showDefaultMsg>
          <label class="custom-file-label" for="selected">Choose file....</label>
        </ng-template>
-->
            </div>
        </div>
    <button [disabled]="!selected.value" id="uploadBtn" class="btn btn-primary" (click)="onUpload(selected)">Upload</button>
        <div class="text-center" *ngIf="message">
            <div class="spinner-border" role="status">
                <span class="sr-only">Loading....</span>
            </div>
            <div>{{ message }}</div>
        </div>
    </div>
</form>

Thanks

Upvotes: 4

Views: 5406

Answers (1)

mwilson
mwilson

Reputation: 12900

I don't believe you can reference the value like that and pick up changes. selected is an HTMLInputElement, not an Observable<HTMLInputElement> or any other thing that is going to emit the value on change.

In the below example, you'll see that the same setup with a text box shows what you would expect on page load, but doesn't actually pickup any changes to the input value.

StackBlitz here

You need to either use ngModel, FormControl, or just create an event for the change event.

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';
  fileName = null;

  onFileChange(evt): void {
    this.fileName = evt.target.files[0].name;
  }
}

Template

<hello name="{{ name }}"></hello>
<input type="text" #myInput value="Init Text" />
<div>Input Text: {{myInput.value}}</div>
<input type="file" (change)="onFileChange($event)" />
<div>name: {{fileName}}</div>

Upvotes: 4

Related Questions