【问题标题】:Pass a DOM event to custom form validator in Angular将 DOM 事件传递给 Angular 中的自定义表单验证器
【发布时间】:2022-11-24 14:23:11
【问题描述】:

我正在尝试使用反应式方法验证表单。我正在使用文件输入从用户那里获取文件。我定义了一个自定义验证器,允许用户在特定条件下上传文件。尝试这样做时,出现错误。验证器不会接收整个事件,而只会接收文件的路径,例如 C:\fakepath\abc.xlsx。我想传递 DOM 事件,以便我可以处理文件的所有属性,如类型、大小等。

这是我的代码:

文件.验证器.ts

import { AbstractControl } from '@angular/forms';

export function ValidateFile(control: AbstractControl) : 
{ [key: string]: boolean } | null {
    const value = control.value;

    if (!value) {
        return null;
    }

    return value.length < 0 && value.files[0].type !== '.xlsx' && value.files[0].size > 5000000
    ? { invalidFile: true } : null;

}

工作表.component.ts

constructor(
private formBuilder: FormBuilder,
private alertService: AlertService
) {
    this.sheetForm = this.formBuilder.group({
    sheetType: ['Select Sheet Type', [Validators.required]],
    sheetUpload: [null, [Validators.required, ValidateFile]],
    sheetDescription: [
      null,
      [
        Validators.required,
        Validators.minLength(10),
        Validators.maxLength(100),
      ],
    ],
  });
}

工作表.component.html

<div class="input-group">
    <label for="sheet-upload">Upload Sheet: </label> &nbsp; &nbsp;
    <input
      id="sheet-upload"
      type="file"
      (change)="handleFileInput($event)"
      formControlName="sheetUpload"
      accept=".xlsx"
    />
    <small
      id="custom-error-message"
      *ngIf="
        (sheetForm.get('sheetUpload').dirty ||
          sheetForm.get('sheetUpload').touched) &&
        sheetForm.get('sheetUpload').invalid
      "
    >
      The file size exceeds 5 MB or isn't a valid excel type. Please
      upload again.
    </small>
</div>

任何帮助,将不胜感激。谢谢!

【问题讨论】:

    标签: javascript angular typescript


    【解决方案1】:

    您可以获得对输入元素的引用并在验证器中使用它。

    <input #sheetUpload ...>
    
    @ViewChild('sheetUpload') fileInput: HTMLInputElement;
    
    private ValidateFile(): ValidatorFn {
    return (control) => {
      const value = control.value;
    
      if (!value || !this.fileInput) {
        return null;
      }
    
      const file = this.fileInput.files[0];
    
      return value.length < 0 && file.type !== '.xlsx' && file.size > 5000000
        ? { invalidFile: file.name }
        : null;
      }
    }
    

    【讨论】:

    • 我正在寻找一种更清洁的方法。
    【解决方案2】:

    不确定这是否是最好的方法,但它有效

    • 创建指令以将本机元素附加到表单控件
    • 验证时从验证器中的本机元素获取文件
    • 而且要使用 formControlName,您需要在父元素中分配一个 formGroup(如果包含在其他父元素中则忽略)
    @Directive({
      selector: '[formControlName]',
    })
    export class NativeElementInjectorDirective implements OnInit {
      constructor(private el: ElementRef, private control: NgControl) {}
    
      ngOnInit() {
        (this.control.control as any).nativeElement = this.el.nativeElement;
      }
    }
    

    文件.验证器.ts

    export function ValidateFile(control: any): { [key: string]: boolean } | null {
      const value = control.value;
      const file = control?.nativeElement?.files[0];
    
      if (!value) {
        return null;
      }
    
      return value.length < 0 && file.type !== '.xlsx' && file.size > 5000000
        ? { invalidFile: true }
        : null;
    }
    
    

    工作表.component.html

    <div class="input-group" [formGroup]="sheetForm">
      <label for="sheet-upload">Upload Sheet: </label> &nbsp; &nbsp;
      <input
        id="sheet-upload"
        type="file"
        (change)="handleFileInput($event)"
        formControlName="sheetUpload"
        accept=".xlsx"
      />
      <small
        id="custom-error-message"
        *ngIf="
          (sheetForm.get('sheetUpload').dirty ||
            sheetForm.get('sheetUpload').touched) &&
          sheetForm.get('sheetUpload').invalid
        "
      >
        The file size exceeds 5 MB or isn't a valid excel type. Please upload again.
      </small>
    </div>
    

    【讨论】:

    • 我不知道为什么,但这似乎对我不起作用。
    • 如果您在验证器中控制日志文件,您能看到文件详细信息吗?
    • 代码没有抛出任何错误。但是,文件变量的值未定义。
    • 您是否已将 NativeElementInjectorDirective 添加到模块声明列表中?
    • 嗨,我没有在声明列表中添加指令。这样做后,我收到一个错误。 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.
    猜你喜欢
    • 2018-01-12
    • 2020-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多