Мне не удается узнать, как отметить все поля формы как затронутые. Основная проблема в том, что если я не касаюсь полей и не пытаюсь отправить форму - ошибка проверки не отображается. У меня есть заполнитель для этого фрагмента кода в моем контроллере.
Моя идея проста:
- пользователь нажимает кнопку отправки
- все поля отмечены как затронутые
- программа форматирования ошибок повторно запускается и отображает ошибки проверки
Если у кого-то есть другие идеи, как показывать ошибки при отправке без реализации нового метода - поделитесь ими. Благодаря!
Моя упрощенная форма:
<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>
И мой контроллер:
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] + ' ';
}
}
}
}
}
angular
angular-reactive-forms
angular2-forms
angular2-formbuilder
Гедрюс Киршис
источник
источник
(<any>Object).values(formGroup.controls)
наObject.keys(formGroup.controls).map(x => formGroup.controls[x])
(from stackoverflow.com/questions/42830257/… )controls
в начале функции, поэтому вместо этого должно быть следующее:if (control.controls) { markFormGroupTouched(control); }
touched
просто означает, что ввод был размыт один раз. Чтобы появились ошибки, мне также пришлось вызватьupdateValueAndValidity()
свои элементы управления.Из Angular 8/9 вы можете просто использовать
this.form.markAllAsTouched();
Чтобы пометить элемент управления и его дочерние элементы управления как затронутые.
AbstractControl doc
источник
Что касается ответа @ masterwork. Я попробовал это решение, но у меня возникла ошибка, когда функция попыталась рекурсивно копать внутри FormGroup, потому что в этой строке передается аргумент FormControl вместо FormGroup:
control.controls.forEach(c => this.markFormGroupTouched(c));
Вот мое решение
источник
Начиная с Angular v8, у вас есть это встроенное с помощью
markAllAsTouched
метода.Например, вы можете использовать его как
См. Официальный документ: https://angular.io/api/forms/AbstractControl#markallastouched
источник
Также будет работать цикл по элементам управления формы и их пометка как затронутые:
источник
formGroup
есть другиеformGroup
sЭто мое решение
источник
У меня была эта проблема, но я нашел «правильный» способ сделать это, несмотря на то, что его нет ни в одном учебнике по Angular, который я когда-либо находил.
В своем HTML-
form
коде добавьте в тег ту же переменную ссылки на шаблон#myVariable='ngForm'
( переменную 'hashtag'), которую используют примеры шаблонных форм, в дополнение к тем, что используются в примерах реактивных форм:<form [formGroup]="myFormGroup" #myForm="ngForm" (ngSubmit)="submit()">
Теперь у вас есть доступ к
myForm.submitted
шаблону, который вы можете использовать вместо (или в дополнение к)myFormGroup.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>
Знайте, что
myForm.form === myFormGroup
это правда ... до тех пор, пока вы не забываете="ngForm"
роль. Если вы используете#myForm
один, это не сработает, потому что для переменной будет задан HtmlElement вместо директивы, управляющей этим элементом.Знайте , что
myFormGroup
видно в машинописном коде компонента в реакционно - Forms учебники, ноmyForm
это не так , если вы не передать его через вызов метода, какsubmit(myForm)
вsubmit(myForm: NgForm): void {...}
. (Обратите вниманиеNgForm
на заглавные буквы в машинописном тексте, но в верблюжьем регистре в HTML.)источник
источник
markAsTouched()
не затрагиваются дочерние элементы?markAsTouched()
не отмечают дочерние элементы - github.com/angular/angular/issues/11774 . TL; DR: Это не ошибка.Я столкнулся с той же проблемой, но я не хочу «загрязнять» мои компоненты кодом, который это обрабатывает. Тем более, что мне это нужно во многих формах, и я не хочу повторять код в разных случаях.
Таким образом, я создал директиву (используя опубликованные ответы). Директива украшает -Метод
onSubmit
NgForm: если форма недействительна, она помечает все поля как затронутые и прерывает отправку. В противном случае обычный onSubmit-Method выполняется нормально.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); }; } }
Применение:
<form (ngSubmit)="submit()" appValidateOnSubmit> <!-- ... form controls ... --> </form>
источник
Это код, который я на самом деле использую.
источник
У меня работает этот код:
источник
Решение без рекурсии
Для тех, кто беспокоится о производительности, я предложил решение, которое не использует рекурсию, хотя по-прежнему выполняет итерацию по всем элементам управления на всех уровнях.
Это решение работает как с FormGroup, так и с FormArray.
Вы можете поиграть с этим здесь: angular-mark-as-touched
источник
согласно @masterwork
машинописный код для угловой версии 8
источник
Вот как я это делаю. Я не хочу, чтобы поля ошибок отображались до тех пор, пока не будет нажата кнопка отправки (или не будет нажата форма).
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>
источник
Я полностью понимаю разочарование ОП. Я использую следующее:
Полезная функция :
Использование :
Обратите внимание, что эта функция еще не поддерживает вложенные элементы управления.
источник
Смотрите этот драгоценный камень . Пока что это самое элегантное решение, которое я видел.
Полный код
источник
источник
Посмотреть:
API
источник
Я сделал версию с некоторыми изменениями в представленных ответах, для тех, кто использует версии более ранние, чем версия 8 angular, я хотел бы поделиться ею с теми, кто будет полезен.
Вспомогательная функция:
Применение:
источник