web-dev-qa-db-fra.com

Angular2: la validation de <input type = "file" /> ne se déclenchera pas lors de la modification du fichier à télécharger

Angular 2 semble avoir des problèmes avec l'exécution de la validation lorsqu'une entrée de fichier change.

J'ai fait un plunk pour illustrer ce problème:

Je fais un formulaire comme un groupe

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

Et dans la fonction validateFile, je lance une alerte et me connecte à la console:

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

Plunkr pour illustrer le problème: https://plnkr.co/edit/Pgcg4IkejgaH5YgbY3Ar?p=preview

La validation s'exécutera lors de l'initialisation de la page mais ne s'exécutera pas à chaque fois que vous modifiez le fichier à télécharger.

Y-a t'il une solution à ce problème?

18
S. Robijns

Je l'ai corrigé en utilisant la réponse kemsky et le commentaire de Sébastien. J'ai fait un ngValueAccessor qui s'enregistre sur chaque entrée avec un fichier type.

Plunkr peut être trouvé ici .

Code le plus pertinent + explication ci-dessous:

Cela ajoute un ControlValueAccessor pour les entrées de fichier qui pourraient faire partie du cadre angular lui-même un jour ( # 7341 ). Une entrée de fichier fonctionne différemment des autres contrôles. Ce morceau de le code s'assure que les fichiers sélectionnés sont lus comme valeur:

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

Et pour la validation "requise", j'ai créé un validateur que j'utilise en ajoutant la méthode de validation statique au fichier FormControl pour ReactiveForms. (ou comme directive pour les formulaires basés sur des modèles).

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

La création de mon formulaire ressemble à ceci:

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

Et pour le html:

<input type="file" formControlName="file"/>
37
S. Robijns

Angular 4+ y a changé les liaisons d'hôtes.

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

L'entrée de type file n'est pas prise en charge actuellement, voir # 7341

2
kemsky