Using reactive form validation with <input type="file"> for an Angular app
Asked Answered
B

4

20

I'm writing a component with a file picker that uploads a file to our CDN. I'm trying to add a reactive form on this component to validate the image input, so I can check against file name/extension etc, and keep it wrapped it in a form so I can keep the benefits of Angulars validation.

My component HTML is

<form class="mt-4" [formGroup]="form">
  <div class="form-group form-inline">
    <label class="btn btn-secondary btn-file">Browse
       <input name="file" type="file" (change)="onChange($event)" formControlName="imageInput"
    </label>

    <p *ngIf="file" class="pl-4 align-middle mb-0">{{file.name}}</p>
  </div>

  <button type="button" class="btn btn-primary">Upload</button>
</form>

And my component code behind is

onChange(event: EventTarget) {
  // file picker code

  this.form = this.formBuilder.group({
      imageInput: [this.file.name, CustomValidators.imageValidator]
  });
}

The CustomValidars.imageValidator only just logs the input at the minute.

When the component is loaded, the error message displays as ERROR DOMException: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.

Basically, I want to use the file input in my reactive form, so I can validate against the filename.

Blizzard answered 19/5, 2017 at 14:41 Comment(2)
This issue is still probably open: github.com/angular/angular.io/issues/3466Eyrir
Check my answer here for a full working example + explanationAreta
R
44

As @ibrahim mention it's not implemented yet, but i got the same problem and solved it using hidden field. on onFileChange method set file.name to hidden field, where you can validate.

   <form class="mt-4" [formGroup]="form">
      <div class="form-group form-inline">
        <label class="btn btn-secondary btn-file">Browse
           <input name="file" type="file" (change)="onFileChange($event)">
           <input type="hidden" name="fileHidden" formControlName="imageInput"/> <!-- Validation Field -->
        </label>

        <p *ngIf="file" class="pl-4 align-middle mb-0">{{file.name}}</p>
      </div>
      <button type="button" class="btn btn-primary">Upload</button>
    </form>



onFileChange($event) {
     let file = $event.target.files[0]; // <--- File Object for future use.
     this.form.controls['imageInput'].setValue(file ? file.name : ''); // <-- Set Value for Validation
}
fileName = '';
this.form = this.formBuilder.group({
      imageInput: [fileName, Validators.required]
});
Rhizopod answered 29/5, 2017 at 9:21 Comment(2)
Nice solution (I also added the file file input as a control so that I could add validation messages)Curie
no databinding solutions included with existing files.Pauperism
A
3

export class myClass implements OnInit {

  myForm = new FormGroup({
    name: new FormControl(''),
    myFile: new FormControl('')
  })

  onFileChange($event) {

    this.myForm.patchValue({
      myFile: $event.target.files[0]
    })
  }

}
<input type="file" (change)="onFileChange($event)">
Aquinas answered 19/10, 2018 at 17:51 Comment(1)
Add some context of answer.Commonwealth
C
3

The value of <input type="file"> is read-only, You need to set the option emitModelToViewChange:false when calling setValue() to avoid that error :

ERROR DOMException: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.

SOLUTION :

this.form.get('<name>').setValue(file, {emitModelToViewChange: false});
Caustic answered 19/6, 2020 at 14:52 Comment(0)
C
-1

Remove formControlName="imageInput" from your <input type="file" and this will solve your problem.

Cashandcarry answered 15/1, 2022 at 9:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.