Ich habe Probleme herauszufinden, wie alle Felder des Formulars als berührt markiert werden können. Das Hauptproblem ist, dass, wenn ich keine Felder berühre und versuche, einen Formularüberprüfungsfehler einzureichen, dieser nicht angezeigt wird. Ich habe einen Platzhalter für diesen Code in meinem Controller.
Meine Idee ist einfach:
- Benutzer klickt auf die Schaltfläche "Senden"
- Alle Felder werden als berührt markiert
- Fehlerformatierer führt erneut aus und zeigt Validierungsfehler an
Wenn jemand eine andere Idee hat, wie Fehler beim Senden angezeigt werden können, ohne eine neue Methode zu implementieren, teilen Sie diese bitte mit. Vielen Dank!
Meine vereinfachte Form:
<form class="form-horizontal" [formGroup]="form" (ngSubmit)="onSubmit(form.value)">
<input type="text" id="title" class="form-control" formControlName="title">
<span class="help-block" *ngIf="formErrors.title">{{ formErrors.title }}</span>
<button>Submit</button>
</form>
Und mein Controller:
import {Component, OnInit} from '@angular/core';
import {FormGroup, FormBuilder, Validators} from '@angular/forms';
@Component({
selector : 'pastebin-root',
templateUrl: './app.component.html',
styleUrls : ['./app.component.css']
})
export class AppComponent implements OnInit {
form: FormGroup;
formErrors = {
'title': ''
};
validationMessages = {
'title': {
'required': 'Title is required.'
}
};
constructor(private fb: FormBuilder) {
}
ngOnInit(): void {
this.buildForm();
}
onSubmit(form: any): void {
// somehow touch all elements so onValueChanged will generate correct error messages
this.onValueChanged();
if (this.form.valid) {
console.log(form);
}
}
buildForm(): void {
this.form = this.fb.group({
'title': ['', Validators.required]
});
this.form.valueChanges
.subscribe(data => this.onValueChanged(data));
}
onValueChanged(data?: any) {
if (!this.form) {
return;
}
const form = this.form;
for (const field in this.formErrors) {
if (!this.formErrors.hasOwnProperty(field)) {
continue;
}
// clear previous error message (if any)
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.touched && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
if (!control.errors.hasOwnProperty(key)) {
continue;
}
this.formErrors[field] += messages[key] + ' ';
}
}
}
}
}
quelle
(<any>Object).values(formGroup.controls)
zuObject.keys(formGroup.controls).map(x => formGroup.controls[x])
(von stackoverflow.com/questions/42830257/… )controls
zu Beginn der Funktion, daher sollte es stattdessen Folgendes sein:if (control.controls) { markFormGroupTouched(control); }
touched
bedeutet nur, dass die Eingabe einmal unscharf war. Um Fehler anzuzeigen, musste ich auchupdateValueAndValidity()
meine Steuerelemente aufrufen .Ab Angular 8/9 können Sie einfach verwenden
this.form.markAllAsTouched();
Markieren eines Steuerelements und seiner untergeordneten Steuerelemente als berührt.
AbstractControl doc
quelle
In Bezug auf die Antwort von @ masterwork. Ich habe diese Lösung ausprobiert, aber es ist ein Fehler aufgetreten, als die Funktion versucht hat, rekursiv in einer FormGroup zu graben, da in dieser Zeile ein FormControl-Argument anstelle einer FormGroup übergeben wird:
control.controls.forEach(c => this.markFormGroupTouched(c));
Hier ist meine Lösung
quelle
In Angular v8 ist dies mithilfe der
markAllAsTouched
Methode integriert.Als Beispiel könnten Sie es wie verwenden
Siehe das offizielle Dokument: https://angular.io/api/forms/AbstractControl#markallastouched
quelle
Das Durchlaufen der Formularsteuerelemente und das Markieren als berührt würde ebenfalls funktionieren:
quelle
formGroup
andereformGroup
sDas ist meine Lösung
quelle
Ich hatte dieses Problem, fand aber den "richtigen" Weg, obwohl es in keinem Angular-Tutorial enthalten war, das ich jemals gefunden habe.
Fügen Sie in Ihrem HTML-Code auf dem
form
Tag dieselbe Vorlagenreferenzvariable#myVariable='ngForm'
('Hashtag'-Variable) hinzu, die in den Beispielen für vorlagengesteuerte Formulare verwendet wird, zusätzlich zu den Beispielen für reaktive Formulare:<form [formGroup]="myFormGroup" #myForm="ngForm" (ngSubmit)="submit()">
Jetzt haben Sie Zugriff auf
myForm.submitted
die Vorlage, die Sie anstelle (oder zusätzlich zu) verwenden könnenmyFormGroup.controls.X.touched
:<div *ngIf="myForm.submitted" class="text-error"> <span *ngIf="myFormGroup.controls.myFieldX.errors?.badDate">invalid date format</span> <span *ngIf="myFormGroup.controls.myFieldX.errors?.isPastDate">date cannot be in the past.</span> </div>
Wisse, dass
myForm.form === myFormGroup
das wahr ist ... solange du den="ngForm"
Teil nicht vergisst . Wenn Sie es#myForm
alleine verwenden, funktioniert es nicht, da die Variable auf das HTML-Element gesetzt wird, anstatt auf die Direktive, die dieses Element steuert.Wissen Sie, dass
myFormGroup
in Ihrer Komponente Typoskript Code gemäß dem Reactive Forms Tutorials sichtbar ist, abermyForm
nicht, wenn Sie es in durch einen Methodenaufruf übergeben, wiesubmit(myForm)
zusubmit(myForm: NgForm): void {...}
. (HinweisNgForm
ist im Typoskript in Titelkappen, in HTML jedoch in Kamelbuchstaben.)quelle
quelle
markAsTouched()
untergeordnete Elemente nicht berührt werden?markAsTouched()
Elemente nicht markiert werden - github.com/angular/angular/issues/11774 . TL; DR: Es ist kein Fehler.Ich bin auf dasselbe Problem gestoßen, möchte meine Komponenten jedoch nicht mit Code "verschmutzen", der dies behandelt. Zumal ich dies in vielen Formen brauche und den Code nicht bei verschiedenen Gelegenheiten wiederholen möchte.
Daher habe ich eine Richtlinie erstellt (unter Verwendung der bisher veröffentlichten Antworten). Die Direktive schmückt die Methode von
onSubmit
NgForm: Wenn das Formular ungültig ist, werden alle Felder als berührt markiert und die Übermittlung abgebrochen. Ansonsten wird die übliche onSubmit-Methode normal ausgeführt.import {Directive, Host} from '@angular/core'; import {NgForm} from '@angular/forms'; @Directive({ selector: '[appValidateOnSubmit]' }) export class ValidateOnSubmitDirective { constructor(@Host() form: NgForm) { const oldSubmit = form.onSubmit; form.onSubmit = function (): boolean { if (form.invalid) { const controls = form.controls; Object.keys(controls).forEach(controlName => controls[controlName].markAsTouched()); return false; } return oldSubmit.apply(form, arguments); }; } }
Verwendung:
<form (ngSubmit)="submit()" appValidateOnSubmit> <!-- ... form controls ... --> </form>
quelle
Dies ist der Code, den ich tatsächlich verwende.
quelle
Dieser Code funktioniert für mich:
quelle
Eine Lösung ohne Rekursion
Für diejenigen, die sich Sorgen um die Leistung machen, habe ich eine Lösung gefunden, die keine Rekursion verwendet, obwohl sie immer noch alle Steuerelemente in allen Ebenen durchläuft.
Diese Lösung funktioniert sowohl mit FormGroup als auch mit FormArray.
Hier können Sie damit herumspielen: Winkelmarkierung als berührt
quelle
gemäß @masterwork
Typoskript-Code für die Winkelversion 8
quelle
Hier ist, wie ich es mache. Ich möchte nicht, dass die Fehlerfelder angezeigt werden, bis die Senden-Schaltfläche gedrückt wird (oder das Formular berührt wird).
import {FormBuilder, FormGroup, Validators} from "@angular/forms"; import {OnInit} from "@angular/core"; export class MyFormComponent implements OnInit { doValidation = false; form: FormGroup; constructor(fb: FormBuilder) { this.form = fb.group({ title: ["", Validators.required] }); } ngOnInit() { } clickSubmitForm() { this.doValidation = true; if (this.form.valid) { console.log(this.form.value); }; } }
<form class="form-horizontal" [formGroup]="form" > <input type="text" class="form-control" formControlName="title"> <div *ngIf="form.get('title').hasError('required') && doValidation" class="alert alert-danger"> title is required </div> <button (click)="clickSubmitForm()">Submit</button> </form>
quelle
Ich verstehe die Frustration des OP vollkommen. Ich benutze folgendes:
Dienstprogrammfunktion :
Verwendung :
Beachten Sie, dass diese Funktion noch nicht für verschachtelte Steuerelemente geeignet ist.
quelle
Sehen Sie dieses Juwel . Bisher die eleganteste Lösung, die ich je gesehen habe.
Vollständiger Code
quelle
quelle
Aussicht:
API
quelle
Ich habe eine Version mit einigen Änderungen in den vorgestellten Antworten erstellt. Für diejenigen, die Versionen verwenden, die älter als Version 8 des Winkels sind, möchte ich sie mit denen teilen, die nützlich sind.
Dienstprogrammfunktion:
Verwendung:
quelle