Es fällt mir schwer, sowohl * ngIf in einem Formular als auch ngFormModel zur Validierung dieses Formulars zu verwenden.
Der Anwendungsfall ist der folgende: Blenden Sie basierend auf Benutzereingaben bestimmte Felder im Formular aus oder deaktivieren Sie sie. Falls diese Eingaben angezeigt werden, müssen sie validiert werden.
Wenn nur eine grundlegende Validierung erforderlich ist, kann ich Folgendes tun:
ngControl
und required
.pattern
verwendet werden. Es ist nicht eckig, aber es funktioniert.Um komplexere Validierungen zu implementieren, habe ich versucht, ngControl
in Verbindung mit ngFormModel
zu verwenden, um benutzerdefinierte Prüfungen zu verwenden. Ich habe Code-Teile verwendet, die auf den folgenden Seiten zu finden sind:
Wie man ein Formular-Validierungsmuster in angle2 hinzufügt (und die Links, auf die dort verwiesen wird)
Angular2-Formulare: Validierungen, ngControl, ngModel usw.
Mein Code lautet wie folgt:
HTML
<div>
<h1>Rundown of the problem</h1>
<form (ngSubmit)="submitForm()" #formState="ngForm" [ngFormModel]="myForm">
<div class="checkbox">
<label>
<input type="checkbox" [(ngModel)]="model.hideField" ngControl="hideField"> Is the input below useless for you ?
</label>
</div>
<div *ngIf="!model.hideField">
<div class="form-group">
<label for="optionalField">Potentially irrelevant field </label>
<input type="text" class="form-control" [(ngModel)]="model.optionalField" ngControl="optionalField" required #optionalField="ngForm">
<div [hidden]="optionalField.valid || optionalField.pristine" class="alert alert-warning">
This input must go through myCustomValidator(), so behave.
</div>
</div>
</div>
<button type="submit" class="btn btn-primary" [disabled]="!formState.form.valid">I can't be enabled without accessing the input :(</button>
<button type="submit" class="btn btn-default">Submit without using form.valid (boo !)</button>
</form>
</div>
TypeScript
import {Component, ChangeDetectorRef, AfterViewInit } from 'angular2/core';
import {NgForm, FormBuilder, Validators, ControlGroup, FORM_DIRECTIVES} from 'angular2/common';
@Component({
selector: 'accueil',
templateUrl: 'app/accueil.component.bak.html',
directives:[FORM_DIRECTIVES],
providers: [FormBuilder]
})
export class AccueilComponent implements AfterViewInit {
private myForm: ControlGroup;
model: any;
constructor(fb: FormBuilder, cdr: ChangeDetectorRef) {
this.cdr = cdr ;
this.model = {} ;
this.myForm = fb.group({
"hideField": [false],
"optionalField": [this.model.optionalField, Validators.compose([this.myCustomValidator])]
});
}
ngAfterViewInit() {
// Without this, I get the "Expression has changed after it was checked" exception.
// See also : https://stackoverflow.com/questions/34364880/expression-has-changed-after-it-was-checked
this.cdr.detectChanges();
}
submitForm(){
alert("Submitted !");
}
myCustomValidator(optionalField){
// Replace "true" by "_someService.someCheckRequiringLogicOrData()"
if(true) {
return null;
}
return { "ohNoes": true };
}
}
Auch wenn die Eingabe mit * ngIf aus der Vorlage entfernt wird, verweist der Konstruktor weiterhin auf das Steuerelement. Was wiederum verhindert, dass ich [disabled] = "! FormState.form.valid" verwende, da myForm
verständlicherweise UNGÜLTIG ist.
Ist das, was ich anstrebe, mit Angular 2 möglich? Ich bin mir sicher, dass dies kein ungewöhnlicher Anwendungsfall ist, aber nach meinem derzeitigen Kenntnisstand kann ich nicht erkennen, wie ich ihn zum Laufen bringen könnte.
Vielen Dank !
Sie können versuchen, die Prüfer auf Ihrem Steuerelement zurückzusetzen. Das heißt, wenn Sie möchten, dass eine neue Gruppe von Validatoren aufgrund einer Statusänderung an ein Steuerelement gebunden wird, definieren Sie die Validatorfunktion neu.
Wenn in Ihrem Fall das Kontrollkästchen aktiviert/deaktiviert ist, soll Folgendes geschehen:
form.valid
aktualisiert wird.Siehe mein plnkr-Beispiel basierend auf Angular.io's Forms Guide
if (optional)
this.heroFormModel.controls['name'].validator = Validators.minLength(3);
else
this.heroFormModel.controls['name'].validator =
Validators.compose([Validators.minLength(3), Validators.required]);
this.heroFormModel.controls['name'].updateValueAndValidity();
Ich bin gerade auf genau dasselbe Problem gestoßen und habe eine Problemumgehung gefunden, die auf manuelles Ein- und Ausschließen der Steuerelemente beruht:
import {Directive, Host, SkipSelf, OnDestroy, Input, OnInit} from 'angular2/core';
import {ControlContainer} from 'angular2/common';
@Directive({
selector: '[ngControl]'
})
export class MyControl implements OnInit, OnDestroy {
@Input() ngControl:string;
constructor(@Host() @SkipSelf() private _parent:ControlContainer) {}
ngOnInit():void {
// see https://github.com/angular/angular/issues/6005
setTimeout(() => this.formDirective.form.include(this.ngControl));
}
ngOnDestroy():void {
this.formDirective.form.exclude(this.ngControl);
}
get formDirective():any {
return this._parent.formDirective;
}
}
Damit dies funktioniert, müssen zunächst alle dynamischen Steuerelemente aus dem Formular ausgeschlossen werden. Einzelheiten finden Sie im plunkr .
Hier ist eine aktualisierte Version für RC4. Ich habe es für meine Zwecke auch in npControl umbenannt.
import { Directive, Host, OnDestroy, Input, OnInit } from '@angular/core';
import { ControlContainer } from '@angular/forms';
@Directive({
selector: '[npControl]'
})
export class NPControlDirective implements OnInit, OnDestroy {
@Input() npControl: string;
constructor(@Host() private _parent: ControlContainer
) { }
ngOnInit(): void {
console.log('include ', this.npControl);
setTimeout(() => this.formDirective.form.include(this.npControl));
}
ngOnDestroy(): void {
console.log('exclude ', this.npControl);
this.formDirective.form.exclude(this.npControl);
}
get formDirective(): any {
return this._parent;
}
}