Angular2:更改要上载的文件时,不会触发<input type ="file"/>的验证

S. *_*jns 18 angular2-forms angular

当文件输入发生变化时,Angular 2似乎在运行验证时遇到麻烦.

我做了一个插图来说明这个问题:

我创建了一个formGroup

this.frm = new FormGroup({
    file: new FormControl("", this.validateFile)
});
Run Code Online (Sandbox Code Playgroud)

在validateFile函数中,我抛出一个警报并记录到控制台:

public validateFile(formControl: FormControl): {[key: string]: any; } {
   alert('Validation ran');
   console.log('Validation ran');
}
Run Code Online (Sandbox Code Playgroud)

Plunkr来说明问题:https://plnkr.co/edit/Pgcg4IkejgaH5YgbY3Ar?p = preview

验证将在初始化页面时运行,但每次更改要上载的文件时都不会运行.

有没有解决这个问题的方法?

S. *_*jns 38

我用kemsky答案和塞巴斯蒂安的评论修正了它.我创建了一个ngValueAccessor,它在每个带有类型文件的输入上注册自己.

Plunkr可以在这里找到.

最相关的代码+解释如下:

这为文件输入添加了一个ControlValueAccessor,有一天它可能是角度框架本身的一部分(#7341).文件输入与其他控件的工作方式不同.这段代码确保将所选文件作为值读取:

import {Directive} from "@angular/core";
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from "@angular/forms";

@Directive({
    selector: "input[type=file]",
    host : {
        "(change)" : "onChange($event.target.files)",
        "(blur)": "onTouched()"
    },
    providers: [
        { provide: NG_VALUE_ACCESSOR, useExisting: FileValueAccessor, multi: true }
    ]
})
export class FileValueAccessor implements ControlValueAccessor {
    value: any;
    onChange = (_) => {};
    onTouched = () => {};

    writeValue(value) {}
    registerOnChange(fn: any) { this.onChange = fn; }
    registerOnTouched(fn: any) { this.onTouched = fn; }
}
Run Code Online (Sandbox Code Playgroud)

对于'required'验证,我创建了一个验证器,我通过将静态验证方法添加到文件FormControl for ReactiveForms来使用.(或作为模板驱动形式的指令).

import {Directive} from "@angular/core";
import {NG_VALIDATORS, Validator, FormControl} from "@angular/forms";

@Directive({
    selector: "[requiredFile]",
    providers: [
        { provide: NG_VALIDATORS, useExisting: FileValidator, multi: true },
    ]
})
export class FileValidator implements Validator {
    static validate(c: FormControl): {[key: string]: any} {
        return c.value == null || c.value.length == 0 ? { "required" : true} : null;
    }

    validate(c: FormControl): {[key: string]: any} {
        return FileValidator.validate(c);
    }
}
Run Code Online (Sandbox Code Playgroud)

构建我的表单如下所示:

private buildForm() {
    this.frm = new FormGroup({
        file: new FormControl("",    [FileValidator.validate])
    });
}
Run Code Online (Sandbox Code Playgroud)

而对于HTML:

<input type="file" formControlName="file"/>
Run Code Online (Sandbox Code Playgroud)


小智 9

Angular 4+改变了主机绑定.

import { Directive, HostListener } from "@angular/core";
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from "@angular/forms";

@Directive({
    selector: "input[type=file]",
    providers: [
        {provide: NG_VALUE_ACCESSOR, useExisting: FileValueAccessorDirective, multi: true}
    ]
})
export class FileValueAccessorDirective implements ControlValueAccessor {
    @HostListener('change', ['$event.target.files']) onChange = (_) => {};
    @HostListener('blur') onTouched = () => {};

    writeValue(value) {}
    registerOnChange(fn: any) { this.onChange = fn; }
    registerOnTouched(fn: any) { this.onTouched = fn; }
}
Run Code Online (Sandbox Code Playgroud)