Angular 5 文件上传:无法在“HTMLInputElement”上设置“值”属性

Posted

技术标签:

【中文标题】Angular 5 文件上传:无法在“HTMLInputElement”上设置“值”属性【英文标题】:Angular 5 file upload: Failed to set the 'value' property on 'HTMLInputElement' 【发布时间】:2018-10-02 21:39:15 【问题描述】:

我有一个用于在 Angular 5 应用程序中上传文件的表单,并且由于我完全从我前段时间编写的代码中复制了它,我可以发誓它以前曾工作过。

这是我的 html 代码:

<form [formGroup]="form" (ngSubmit)="onSubmit()">
        <div class="form-group">
            <label>File:</label>
            <input #theFile type="file" (change)="onFileChange($event)" accept=".png" class="form-control" 
                    formControlName="content" />
            <input type="hidden" name="fileHidden" formControlName="imageInput"/>

                    <!-- [(ngModel)]="model.content" -->
            
            <div class="alert alert-danger" *ngIf="!form.prestine && form.controls.content.errors?.noFile">
                Please provide a photo.
            </div>
            <div class="alert alert-danger" *ngIf="form.controls.content.errors?.fileTooBig">
                The file is too big and won't uploaded. Maximum allowed size is 500kb.
            </div>
        </div>
        <div class="form-group">
            <label>Notes</label>
            <textarea type="text" class="form-control" formControlName="notes" [(ngModel)]="model.notes" > </textarea>
        </div>
        <button type="submit" class="btn btn-primary" [disabled]="!form.valid">Submit</button>
        <button class="btn btn-default" type="button" (click)="close(false);">Cancel</button>
    </form>

这里是fileUpload控件中使用的“onFileChange”方法:

onFileChange($event)
  
    if ($event.target.files.length > 0)
    
        let ftu: File = null;
        ftu = $event.target.files[0];
        this.form.controls['content'].setValue(ftu);
        this.model.content = $event.target.files[0];
    
  

这是我编写和使用的自定义验证器的代码:

import  FormControl  from '@angular/forms';

export class SekaniRootImageValidators

    static sizeTooBig(control: FormControl)
    
        if (!control.value)
        
            return  noFile : true 
        
        else  if (control.value[0].size > 505000)
        
            return  fileTooBig: true
        
        return null;

    

现在的问题是,只要我在输入控件中选择一个文件,我就会在控制台中收到以下错误消息:

ERROR DOMException: 无法设置 'value' 属性 'HTMLInputElement':这个输入元素接受一个文件名,它可以 只能以编程方式设置为空字符串。

这段代码以前工作过,所以我什至不知道从哪里开始。任何帮助表示赞赏!

注意:这是一个有效答案的链接:Angular2: validation for <input type="file"/> won't trigger when changing the file to upload

【问题讨论】:

【参考方案1】:

就我而言,我刚刚删除了 formControlName:

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

还有.ts:

onFileChange(event) 
    const reader = new FileReader();

    if (event.target.files && event.target.files.length) 
      const [file] = event.target.files;
      reader.readAsDataURL(file);
      reader.onload = () => 
        this.data.parentForm.patchValue(
          tso: reader.result
        );

        // need to run CD since file load runs outside of zone
        this.cd.markForCheck();
      ;
    
  

【讨论】:

不知为什么formcontrolname上不去? 如果您有formControlName 并且您尝试以编程方式设置该值,您会得到上述错误。因此,如果您的文件输入在FormGroup 中需要验证器,并且您尝试测试文件上传,则会失败,因为不会设置值并且您无法设置它。【参考方案2】:

就像错误所说的那样,您只能将空字符串设置为文件输入值以清除选择。否则可能会带来安全风险。我无法想象该代码是如何工作的。也许在一些非标准(坏)浏览器中?

如果您只是删除该行,该代码是否应该工作,为什么您需要为它已经拥有的输入设置相同的值?

编辑:似乎需要自定义 ValueAccessor 来验证文件输入。另一个答案中的解决方案:Angular2: validation for <input type="file"/> won't trigger when changing the file to upload

【讨论】:

因为我想对该输入使用自定义验证器。验证器将附加到表单控件对象,否则验证器如何知道输入控件的值才能对其进行验证? 你不需要手动设置输入的值来验证器工作.. 谷歌了一下,看起来文件输入不支持开箱即用。您至少需要添加一个自定义 ValueAccessor。这个答案可能会有所帮助:***.com/questions/41889384/…【参考方案3】:

首先你应该从你的元素中删除“formControlName”类型文件, 因为它得到了字符串 然后在你的 ts 文件中你应该添加这个

if (event.target.files && event.target.files.length > 0) 
  const file = (event.target.files[0] as File);
  this.yourForm.get('image').setValue(file);
  console.log(this.yourForm.get('image').value);

【讨论】:

从元素中删除“formControlName”解决了我的问题。谢谢!【参考方案4】:

通过为文件设置 2 个输入来实现这一点。这是我的做法:

  this.myForm= this.formBuilder.group(
      fileSource: ['', Validators.required],
      fileName: '',
    )

HTML

<input type="file" formControlName='fileSource' (change)="onFileSelected($event)"/>

打字稿

  onFileSelected(event) 
    if(event.target.files.length > 0) 
     
       this.myForm.patchValue(
          fileName: event.target.files[0],
       )
     
  

submit()
    const formData = new FormData();
    formData.append('file', this.myForm.get('fileName').value);
   
    this.http.post('http://localhost:3000/upload', formData)
      .subscribe(res => 
        console.log(res);
        alert('Uploaded Successfully.');
      )
  

【讨论】:

【参考方案5】:

不要将输入属性的值设置为所选文件。相反,只需将文件内容设置为变量并单独附加到请求对象。 对于文件输入,只需将 even.target.value 分配为输入值,以便用户看到实际选择的文件。

【讨论】:

以上是关于Angular 5 文件上传:无法在“HTMLInputElement”上设置“值”属性的主要内容,如果未能解决你的问题,请参考以下文章

Spring + Angular无法两次上传相同的文件

Angular / Nest / GraphQL - 无法上传文件(400 错误请求或 500)

在 asp.net core 2.0 中使用 angular 5 上传文件。文件为空

在 Angular 中上传文件?

使用 Angular 和 php 选择文件、裁剪和上传

Angular 6 - 上传后获取 Firebase 存储文件的下载 URL