Скидання форми Angular 5 FormGroup не скидає валідатори


79

У мене є форма на моїй сторінці, і коли я зателефоную, FormGroup.reset()вона встановлює для класу форми значення, ng-pristine ng-untouchedале FormControl.hasError(...)все одно повертає істину. Що я тут роблю не так?

Шаблон

<form [formGroup]="myForm" (ngSubmit)="submitForm(myForm)">
  <mat-form-field>
    <input matInput formControlName="email" />
    <mat-error *ngIf="email.hasError('required')">
      Email is a required feild
    </mat-error>
  </mat-form-field>
  <mat-form-field>
    <input matInput type="password" formControlName="password" />
    <mat-error *ngIf="password.hasError('required')">
      Password is a required feild
    </mat-error>
  </mat-form-field>
  <button type="submit">Login</button>
</form>

Компонент

export class MyComponent {
  private myForm: FormGroup;
  private email: FormControl = new FormContorl('', Validators.required);
  private password: FormControl = new FormControl('', Validators.required);

  constructor(
    private formBuilder: FormBuilder
  ) {
    this.myForm = formBuilder.group({
      email: this.email,
      password: this.password
    });
  }

  private submitForm(formData: any): void {
    this.myForm.reset();
  }
}

Планкер

https://embed.plnkr.co/Hlivn4/


1
Чи можете ви спробувати також зателефонувати this.myForm.markAsUntouched();?
— Вибухові таблетки

Це не працює і не повинно бути необхідним на підставі документації. ( v2.angular.io/docs/ts/latest/api/forms/index/… )
— efarley


Відповіді:


148

Він ( FormGroup) поводиться коректно. Для вашої форми потрібні ім’я користувача та пароль, тому, коли ви скидаєте форму, вона повинна бути недійсною (тобто форма без імені користувача / пароля недійсна).

Якщо я правильно розумію, ваша проблема тут полягає в тому, чому червоні помилки не з’являються під час першого завантаження сторінки (де форма ТАКОЖ недійсна), а з’являються, коли ви натискаєте кнопку. Ця проблема особливо помітна, коли ви використовуєте Матеріал.

AFAIK, <mat-error>перевірте правильність FormGroupDirective, ні FormGroup, і скидання FormGroupне скидає FormGroupDirective. Це трохи незручно, але для очищення <mat-error>вам також потрібно буде скинути налаштування FormGroupDirective.

Для цього у своєму шаблоні визначте змінну як таку:

<form [formGroup]="myForm" #formDirective="ngForm" 
  (ngSubmit)="submitForm(myForm, formDirective)">

А у класі вашого компонента зателефонуйте formDirective.resetForm():

private submitForm(formData: any, formDirective: FormGroupDirective): void {
    formDirective.resetForm();
    this.myForm.reset();
}

Випуск GitHub: https://github.com/angular/material2/issues/4190


Цю проблему дійсно потрібно вирішити, як ви вже казали, це досить незручно, коли потрібно використовувати цей обхідний шлях ... Зробимо це, хороший улов та подяка за рішення
— schankam

2
У моєму випадку у мене була дуже унікальна ситуація, коли мені потрібно було скинути "надіслане", не очищаючи значення форми (що resetForm ()) робило зі мною. Щоб обійти це, я це зробив (<any>formDirective).submitted = false;. Якийсь брудний хак, але, дивлячись на вихідний код, немає очевидної причини, яку потрібно було б прочитати лише у визначенні їх машинопису.
— scourge192

2
Прочитайте випуск github, де офіційною відповіддю було "не мій відділ". Досить кульгавий, я очікую від співробітників Google кращого.
— ctilley79,

З кутовим 7.2.2:Argument of type NgForm is not assignable to type FormGroupDirective
— Мсанфорд,

1
Після тестування з багатьма рішеннями, це просто ідеально працює !!
— JP Бала Крішна

27

Прочитавши коментарі, це правильний підхід

// you can put this method in a module and reuse it as needed
resetForm(form: FormGroup) {

    form.reset();

    Object.keys(form.controls).forEach(key => {
      form.get(key).setErrors(null) ;
    });
}

Не було потреби дзвонити form.clearValidators()


8
Це просто видалить валідатори, а не скине їх.
— Максимільон Бартанго

2
Щоб очистити валідатори this.loginform.clearValidators (), а потім встановіть для помилок
— елемента

чудово працює з Angular 9. Ще щось не так mbue
— Петрос

22

На додаток до рішення Гаррі Ніна, якщо ви хочете отримати доступ до формиDirective у своєму компоненті, не натискаючи кнопку форми, тоді:

Шаблон:

<form 
  ...
  #formDirective="ngForm" 
>

Компонент:

import { ViewChild, ... } from '@angular/core';
import { NgForm, ... } from '@angular/forms';

export class MyComponent {
 ...
 @ViewChild('formDirective') private formDirective: NgForm;

  constructor(... )

  private someFunction(): void { 
    ...
    formDirective.resetForm();
  }
}

1
Я думаю, що це краща відповідь. той, що позначений як відповідь, повинен передати локальну локальну змінну коду позаду, не бажано. Але ця відповідь дала дуже хорошу інформацію про те, як працює форма.
— Сем

Для Angular 8 директива `@ViewChild приймає два параметри. Іншим параметром, крім рядка 'formDirective', є властивості метаданих. Для отримання додаткової інформації див. Angular.io/api/core/ViewChild#description .
— Джонатан Кардоз,

чудова відповідь, але його не тільки скидає валідатори, але і скидає всі значення (введені користувачами) у формі.
— ukie

3

Наведене нижче рішення працює для мене при спробі скинути певний контролер форми у групі форм -

 this.myForm.get('formCtrlName').reset();
 this.myForm.get('formCtrlName').setValidators([Validators.required, Validators.maxLength(45), Validators.minLength(4), Validators.pattern(environment.USER_NAME_REGEX)]);
 this.myForm.get('formCtrlName').updateValueAndValidity();

1

Я виявив, що після виклику resetForm () і reset (), надісланий не скидався і залишався як істинний, викликаючи повідомлення про помилки. Це рішення спрацювало для мене. Я знайшов його під час пошуку рішення для виклику select () та focus () на вхідному тегу, який також не працював належним чином. Просто оберніть свої рядки в setTimeout (). Я думаю, що setTimeout змушує Angular виявляти зміни, але я можу помилитися. Це трохи хак, але робить трюк.

<form [formGroup]="myFormGroup" #myForm="ngForm">
    …
    <button mat-raised-button (click)="submitForm()">
</form>
submitForm() { 
    …
    setTimeout(() => {
        this.myForm.resetForm();
        this.myFormGroup.reset();
    }, 0);
}

Знайшов цю відповідь, провівши цілий день. setTimeout () допоміг вирішити цю проблему. Якщо ви можете додати якийсь опис того, як працює цей "хак", це буде корисно. Випробувано кутовим 7.2.8
— Раджендра Торат

1

Додати властивість -

@ViewChild(FormGroupDirective) formGroupDirective: FormGroupDirective;

і використовувати це замість this.myForm.reset();

this.formGroupDirective.resetForm();

Це скине відображення помилок, а також виконає роботу form.reset (). Але форма разом із полями все одно відображатиме ng-invalidклас

Перевірте цю відповідь для отримання детальної інформації - https://stackoverflow.com/a/56518781/9262627


1

form.reset() не працюватиме на спеціальному контролі форми, як Angular Material, тому функція працює не так, як очікувалося.

Моє вирішення цього питання приблизно таке

    this.form.reset();
    for (let control in this.form.controls) {
      this.form.controls[control].setErrors(null);
    }

this.form.reset() проблема з цим полягає в тому, що він скине ваші значення контролю форми, але не помилки, тому вам потрібно скинути їх окремо за цим рядком коду

for (let control in this.form.controls) {
      this.form.controls[control].setErrors(null);
    }

З цим вам не потрібно використовувати, FormGroupDirectiveщо є чистішим рішенням для мене.

Випуск Github: https://github.com/angular/angular/issues/15741


0

У мене також були ті самі проблеми. Моя проблема полягала в тому, що я використовував mat-form-fieldі formGroup. Після скидання submittedпрапор форми не скидався.

Отже, рішення, яке працювало для мене, полягає у додаванні директиви ngFormразом з formGroupта передачі onSubmit(form). Додано @ViewChild('form') form; в компонент, а потім я використав this.form.resetForm();


0

У мене нічого з вище не працювало (Angular 7.2, Angular Material 7.3.7).

Спробуйте передати з методом подання подію на перегляд:

<form [formGroup]="group" (ngSubmit)="onSubmit($event)">
    <!-- your form here -->
</form>

Потім використовуйте його для скидання currentTargetта форми після:

public onSubmit(event): void {
  // your code here
  event.currentTarget.reset()
  this.group.reset()
}

0

Просте виправлення: використовуйте кнопку type="reset"та функціонуйте submitForm()разом

<form [formGroup]="MyForm" (ngSubmit)="submitForm()">
  <input formControlName="Name">
  <mat-error>  
    <span *ngIf="!tunersForm.get('Name').value && tunersForm.get('Name').touched"></span>  
  </mat-error>
  <button type="reset" [disabled]="!MyForm.valid" (click)="submitForm()">Save</button>
</form>

0

Мені не пощастило зі скиданням директиви форми. Але Ви також можете змінити стан введення на очікуваний, щоб зробити це також.

this.myForm.get("email").reset();
this.myForm.get("password").reset();

0

Для тих, кому це може допомогти, я запускаю Angular 9.1.9, і я не хотів скидати форму / керувати лише загальною валідністю форми, тому я просто запустив:

this.registerForm.setErrors(null);

... де registerForm: FormGroupі що скидає помилки форми, що призводить до:

this.registerForm.valid

... повертаючись true.

Те саме можна зробити для елементів управління:

this.registerForm.get('email').setErrors(null)

Як тільки форма торкається, ці помилки все одно переоцінюються, тому, якщо це недостатньо добре, можливо, вам знадобиться логічний прапор для подальшого закріплення саме тоді, коли ви хочете почати відображати / приховувати інтерфейс помилки.

Мені не потрібно було торкатися директиви у моєму випадку.


0
 resetForm() {
    this.myFormGroup.reset();
    this.myFormGroup.controls.food.setErrors(null);
    this.myFormGroup.updateValueAndValidity();
  } 

1
Хоча цей код може відповісти на питання, надання додаткового контексту щодо того, як та / або чому він вирішує проблему, покращило б довгострокове значення відповіді.
— Андреас,

-4

Перемістіть функцію надсилання із форми на кнопку та додайте типи до кнопок:

<form [formGroup]="createForm">
  <button (click)="submitForm()" type="submit">Submit</button>
  <button (click)="createForm.reset()" type="reset">Reset</button>
</form>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.