【问题标题】:Angular2: validation for <input type="file"/> won't trigger when changing the file to uploadAngular2:更改要上传的文件时不会触发 <input type="file"/> 的验证
【发布时间】:2017-06-12 20:44:26
【问题描述】:

当文件输入发生变化时,Angular 2 似乎无法运行验证。

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

我制作了一个类似的formGroup

this.frm = new FormGroup({
    file: new FormControl("", this.validateFile)
});

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

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

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

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

有没有办法解决这个问题?

【问题讨论】:

    标签: angular angular2-forms


    【解决方案1】:

    目前不支持file类型的输入,见#7341

    【讨论】:

    • 不支持,但你可以让它工作。在链接的讨论中有一个如何做到这一点的例子。
    【解决方案2】:

    我使用凯姆斯基回答和塞巴斯蒂安的评论修复了它。 我制作了一个 ngValueAccessor,它在每个输入上使用类型文件注册自己。

    Plunkr 可以在here找到。

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

    这为文件输入添加了一个 ControlValueAccessor,它可能有一天会成为 Angular 框架本身的一部分 (#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; }
    }
    

    对于“必需”验证,我制作了一个验证器,我通过将静态验证方法添加到 ReactiveForms 的 FormControl 文件中来使用它。 (或作为模板驱动表单的指令)。

    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);
        }
    }
    

    构建我的表单如下所示:

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

    对于 html:

    <input type="file" formControlName="file"/>
    

    【讨论】:

    • 您好,感谢您的帮助。我尝试在 Angular 4.3 上运行它,但它不起作用。首先,在我上传文件后它仍然无效,然后在提交后我的“文件”字段只是空字符串。我需要改变一些东西吗?再次感谢您,
    • @S.Robijns 我没有 plunker 可以展示,只是什么也没发生。您是否成功在 onSubmit() 函数上获取文件对象?谢谢。
    • @S.Robijns 这在 Angular 5+ 中不起作用这里是示例 angular-input-flie-validation-reactive-form
    • 无需自定义required 验证。您可以只使用 Angular 的 Validators.required 验证器,它在后台使用此功能:github.com/angular/angular/blob/…
    【解决方案3】:

    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; }
    }
    

    【讨论】:

    • 在 Angular 4 中似乎没有变化,看起来 HostBinding 和 HostListener 一直都在。两种方式都有效,但根据风格指南,这确实是首选(angular.io/guide/styleguide)
    • 刚刚遇到一个案例,证明使用主机绑定肯定更好,因为它们可以被继承,而当你把它放在装饰器中时它不能。更多信息:medium.com/@ttemplier/… 稍后我可能会修改我的答案
    • @MrBoJangles 是的 idd.. 不要再指望它了,我的朋友,时间至关重要 :)
    • @Fritz 这在 Angular 5+ 中不起作用这里是示例 angular-input-flie-validation-reactive-form
    猜你喜欢
    • 1970-01-01
    • 2016-05-25
    • 2011-04-25
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多