Скидання форми 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.