typescript 无法设置HTMLinputElement的值属性:此输入元素接受文件名,该文件名只能通过编程方式设置为空字符串

kknvjkwl  于 2023-01-18  发布在  TypeScript
关注(0)|答案(1)|浏览(219)

当我尝试上传图像时,我收到了问题标题中的错误消息:
这是我的模板

<input type="file" formControlName="avatar" accept=".jpg, .jpeg .svg"
   #fileInput (change)="uploadImage($event)" />

<div class="avatar-preview">
  <ng-template #selectedImage>
    <div style.backgroundImage="{{'url('+ imageUrl +')'}}"></div>
  </ng-template>
</div>
<button (click)="fileInput.click()"></button>

这是我的组件ts

@ViewChild('fileInput') el: ElementRef;
imageUrl: string = "";

this.profileForm = new FormGroup({
  avatar: new FormControl(null)
});

public uploadImage(event) {
    let reader = new FileReader();
    let file = event.target.files[0];
    if (event.target.files && event.target.files[0]) {
      reader.readAsDataURL(file);
      reader.onload = () => {
        this.imageUrl = reader.result as string;
        this.profileForm.patchValue({
          avatar: reader.result
        });
      }
    }
    this.cd.markForCheck(); 
}
ozxc1zmp

ozxc1zmp1#

Angular不包含用于文件输入的ControlValueAccessor。这意味着它正在使用FormControl中定义的DefaultValueAccessor,该DefaultValueAccessor尝试将avatar的值写入控件。FileInputControl不允许这样做。
或者您应该实现一个,然后可以删除uploadImage函数,因为它将被移动到ControlValueAccessor
或者删除formControlName="avatar",并且不要使用React形式,因为无论如何您都要自己处理事件。
示例(未测试,您可能需要将其设置为组件或更改选择器,因为这可能与DefaultValueAccessor选择器冲突):

@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 ) {
  }

}

可选地,你也可以将你当前的处理添加到这个指令中(而不是调用this.onChange(file);)。

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

相关问题