[Solved]-"failed to set the 'value' property on 'htmlinputelement': this input element accepts a filename, which may only be programmatically set to the empty string."


"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."

Error Solution:

When encountering the error message 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., it indicates that there's an issue with setting the value property of an HTML input element.

To address this error, follow these steps:

  1. Ensure that you're setting the value property of the input element correctly according to its type. If it's a file input, you can only set its value programmatically to an empty string or the filename of a selected file.
  2. Check if there are any event listeners or scripts modifying the value property of the input element. Make sure that they are not attempting to set a value that is not allowed, such as a non-empty string for a file input.
  3. If you need to clear the value of the input element programmatically, set its value to an empty string ("").
  4. Review your code to ensure that you're handling file inputs correctly, especially when setting their values dynamically.
  5. If you're using frameworks or libraries, make sure they are not conflicting with the behavior of file inputs.

In your component's HTML file, add an event listener to listen for changes:

<input type="file" (change)="onFileChange($event)" #file formControlName="imageName">

In your component's TypeScript file, the following function will create a new file with the updated file name:

onFileChange(event) {
  //console.log(event.target.files[0].name)
  var blob = event.target.files[0].slice(0, event.target.files[0].size, 'image/png'); 

  const newFile = new File([blob], this.dat.imageName, {type: 'image/png'})
  //console.log(newFile)
}

This preserves the original file name on input, but you can utilize newFile in your POST/PUT request to be sent to the backend.

As the error suggests, setting anything other than an empty string to a file input's value could pose security risks, hence why the code likely never worked. It might have functioned in some non-standard (poor) browsers, but it's not recommended.

Removing the line should theoretically work, as setting the same value to the input that it already has seems unnecessary.

However, it appears that a custom ValueAccessor is required for validating file inputs, as indicated in another answer.

Angular lacks a ControlValueAccessor for file inputs. This means it defaults to the DefaultValueAccessor, which attempts to write the value of the avatar to the control. However, this is not permitted for a FileInputControl.

You have a couple of options:

  • Implement a custom ControlValueAccessor. This would involve moving your uploadImage function into the ControlValueAccessor.
  • Alternatively, remove formControlName="avatar" and refrain from using reactive forms since you're handling the events manually anyway.

Here's an example of a custom ControlValueAccessor:

@Directive({
  selector: 'input[type=file][formControlName]',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: FileUploadAccessor,
      multi: true
    }
  ]
})
export class FileUploadAccessor implements ControlValueAccessor {
  private onChange: Function;

  @HostListener('change', ['$event.target.files']) emitFiles( event: FileList ) {
    const file = event && event.item(0);
    this.onChange(file);
  }

  constructor( private host: ElementRef<HTMLInputElement> ) {
  }

  writeValue( value: null ) {
    // clear file input
    this.host.nativeElement.value = '';
  }

  registerOnChange( fn: Function ) {
    this.onChange = fn;
  }

  registerOnTouched( fn: Function ) {
  }

}

You can also add your current processing to this directive instead of calling this.onChange(file);. For example:

let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
  this.onChange(reader.result as string);
}