Angular NgForm: сброс точного значения поля формы не делает его действительным

У меня есть форма по шаблону компонента:

<form (ngSubmit)="submitLogin(loginForm)" #loginForm="ngForm">
  <mat-input-container>
    <input matInput [placeholder]="'User Name'" ngModel name="username" autofocus required>
  </mat-input-container>
  <br>
  <mat-input-container>
    <input matInput [placeholder]="'Password'" ngModel type="password" name="password" required>
  </mat-input-container>
  <br>
  <button [disabled]="loginForm.invalid" mat-raised-button type="submit">
    Login
  </button>
</form>

А вот обработчик отправки моего компонента:

public submitLogin(loginForm: NgForm) {
  return this.authService.login(loginForm.value)
    .subscribe(
      res => this.router.navigate(['/customers']),
      error => loginForm.controls.password.reset() // this place!
    );
}

Он работает, и при ошибке входа в систему (передача случайных значений) я вижу

введите описание изображения здесь

Вопрос. Как я могу сбросить точные значения полей формы и сделать их по-настоящему первозданными и нетронутыми? Таким образом, он должен быть действительным, не отмечая его красной «недопустимой» рамкой в ​​пользовательском интерфейсе.

Сразу после loginForm.controls.password.reset() я вижу, что loginForm.controls.password.touched - это ложь, а loginForm.controls.password.pristine - истина, но я также вижу, что loginForm.controls.password.status является "НЕВЕРНО". Если я взломаю его и напрямую присвою значение "VALID" свойству status, красная недопустимая граница исчезнет, ​​но это нарушит аннулирование потерянного фокуса, если я сосредоточусь на этом поле, а затем уйду без каких-либо Вход. Должен быть законный способ сбросить заполненную форму и одновременно сделать ее действительной.


person dhilt    schedule 29.12.2017    source источник


Ответы (2)


Кажется, это известная проблема. Согласно this состояние ошибки рассчитывается как:

isInvalid && (isTouched || isSubmitted)

Итак, когда вы отправили свою форму, флаг isSubmitted установлен на true, таким образом, условие выполнено, и ваше поле отображается красным. Есть некоторые обходные пути: если бы вы сбросили всю форму, вы могли бы вместо этого использовать resetForm, но здесь вы хотите сбросить только одно поле, поэтому ...

Существует предложение по использованию < strong> ErrorStateMatcher :

<input matInput 
   [placeholder]="'Password'" 
   ngModel type="password" 
   name="password" required 
   [errorStateMatcher]="matcher">

ErrorStateMatcher:

export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    // show errors when touched and invalid
    return (control.invalid && control.touched);
  }
}

и объявите ErrorStateMatcher в своем TS:

matcher = new MyErrorStateMatcher();

Кажется, работает: StackBlitz

person AJT82    schedule 30.12.2017
comment
Спасибо за демонстрацию и объяснения! Но проблема с нарушением аннулирования события потери фокуса все еще существует. Я разветвил ваш StackBlitz (ссылка), чтобы продемонстрировать, что я могу легко достичь того же результата с просто установка loginForm.controls.password.setErrors(null) (тот же подход, что и деструктивная установка loginForm.controls.password.status = "VALID"). Но мне нужно сделать это поле недействительным, когда я сосредоточусь на нем, а затем оставлю его без каких-либо изменений. - person dhilt; 30.12.2017
comment
Ну, я предлагал сначала loginForm.controls.password.setErrors(null) в моем сообщении, но заметил, что кнопка активируется после сброса, поскольку ошибки удаляются, и пароль больше не требуется :) Но вернемся к вашему вопросу, вы имеете в виду, что хотите показать ошибку, когда touched? stackblitz.com/edit/ угловой-hbq2uv-z3xxvp? file = app / - person AJT82; 30.12.2017
comment
Да, с вашим последним обновлением проблема была решена, большое спасибо! - person dhilt; 30.12.2017
comment
Отлично, рад слышать! Я обновлю свой ответ соответственно :) - person AJT82; 30.12.2017

Вы можете использовать markAs существующие функции

Что-то вроде этого

this.loginForm.controls.password.reset()
this.loginForm.controls.password.markAsPristine()
this.loginForm.controls.password.markAsUntouched()
this.loginForm.controls.password.updateValueAndValidity()

Это фактические функции API, когда вы хотите обеспечить соблюдение определенного состояния и не хотите полностью зависеть от решения Angular о том, каким должно быть состояние поля.

Проверьте здесь, как лучше использовать метод updateValueAndValidity

person Hugo Noro    schedule 29.12.2017
comment
К сожалению, это не имеет значения, потому что (как я уже упоминал в вопросе) элемент управления, который был сброшен, уже нетронутый. Проблема в его статусе, который остается НЕДЕЙСТВИТЕЛЬНЫМ ... - person dhilt; 29.12.2017
comment
Я отредактировал свой ответ, включив в него дополнительный вызов, который решает вашу проблему. Также включена ссылка на документацию по angular, где вы можете проверить ее использование. - person Hugo Noro; 29.12.2017