2017-01-27 21 views
7

Angular 2 wydaje się mieć problemy z uruchomieniem sprawdzania poprawności, gdy dane wejściowe ulegną zmianie.Angular2: sprawdzanie poprawności dla <typ wejściowy = "plik" /> nie będzie wyzwalane podczas zmiany pliku do przesłania

Zrobiłem upadać, aby zilustrować ten problem:

zrobię formGroup jak

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

iw funkcji validateFile rzucam alert i zalogować się do konsoli:

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

Plunkr do zilustrowania problemu: https://plnkr.co/edit/Pgcg4IkejgaH5YgbY3Ar?p=preview

Sprawdzanie poprawności będzie uruchamiane podczas inicjowania strony, ale nie będzie uruchamiane za każdym razem, gdy zmienisz plik do przesłania.

Czy istnieje rozwiązanie tego problemu?

Odpowiedz

19

Naprawiłem go za odpowiedź kemsky i Sebastien za komentarz. Zrobiłem ngValueAccessor, który rejestruje się na każdym wejściu z plikiem typu.

Plunkr można znaleźć here.

Najbardziej odpowiedni kod + wyjaśnienie poniżej:

To dodaje ControlValueAccessor wejść plików, które mogą być częścią ram kątowej sama kiedyś (#7341). Dane wejściowe pliku różnią się od innych elementów sterujących. Ten fragment kodu pilnuje wybrane pliki są odczytywane jako wartość:

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

A dla „wymagana” walidacji Zrobiłem walidator który używam dodając statycznej metody sprawdzania poprawności do FormControl plików dla ReactiveForms. (lub jako dyrektywa dla formularzy opartych na szablonach).

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

budowy mój formularz wygląda następująco:

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

A dla HTML:

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

Dziękuję bardzo za dostarczenie tej próbki kodu. To właśnie uratowało mój dzień. – Brandon

+0

Przydatne. Thansk! – user3757628

+0

To działało. Dziękuję Ci! – Sagar

2

wejściami typu file nie jest obsługiwany obecnie zobaczyć #7341

+1

Nie jest obsługiwany, ale można go uruchomić. W połączonej dyskusji znajduje się przykład tego, jak to zrobić. – Sebastian

4

kątowa 4+ zmieniła tam hostbindings.

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

Wygląda na to, że nie zmienił się w kancie 4, wygląda na to, że HostBinding en HostListener zawsze był w pobliżu. Oba sposoby działają, ale zgodnie z przewodnikiem po stylach ten jest rzeczywiście preferowany (https://angular.io/guide/styleguide) –

+0

Po prostu wpadł na sprawę, która udowodniła, że ​​zdecydowanie lepiej jest używać wiązań hosta, ponieważ mogą one być dziedziczone i kiedy umieść go w dekoratorze, którego nie może. Więcej tutaj: https://medium.com/@ttemplier/angular2-decorators-and-class-inheritance-905921dbd1b7 Prawdopodobnie zmienię moją odpowiedź kiedyś później –