Как я могу вручную установить поле формы Angular как недействительное?

191

Я работаю над формой входа в систему, и если пользователь вводит неверные учетные данные, мы хотим пометить поля электронной почты и пароль как недействительные и отобразить сообщение о том, что вход не выполнен. Как мне сделать эти поля недействительными из наблюдаемого обратного вызова?

Шаблон:

<form #loginForm="ngForm" (ngSubmit)="login(loginForm)" id="loginForm">
  <div class="login-content" fxLayout="column" fxLayoutAlign="start stretch">
    <md-input-container>
      <input mdInput placeholder="Email" type="email" name="email" required [(ngModel)]="email">
    </md-input-container>
    <md-input-container>
      <input mdInput placeholder="Password" type="password" name="password" required [(ngModel)]="password">
    </md-input-container>
    <p class='error' *ngIf='loginFailed'>The email address or password is invalid.</p>
    <div class="extra-options" fxLayout="row" fxLayoutAlign="space-between center">
     <md-checkbox class="remember-me">Remember Me</md-checkbox>
      <a class="forgot-password" routerLink='/forgot-password'>Forgot Password?</a>
    </div>
    <button class="login-button" md-raised-button [disabled]="!loginForm.valid">SIGN IN</button>
     <p class="note">Don't have an account?<br/> <a [routerLink]="['/register']">Click here to create one</a></p>
   </div>
 </form>

Способ входа:

 @ViewChild('loginForm') loginForm: HTMLFormElement;

 private login(formData: any): void {
    this.authService.login(formData).subscribe(res => {
      alert(`Congrats, you have logged in. We don't have anywhere to send you right now though, but congrats regardless!`);
    }, error => {
      this.loginFailed = true; // This displays the error message, I don't really like this, but that's another issue.
      this.loginForm.controls.email.invalid = true;
      this.loginForm.controls.password.invalid = true; 
    });
  }

В дополнение к установке флага входных данных неверно, я попытался установить email.validфлаг в false, а также установить значение loginForm.invalidtrue. Ни один из них не заставляет входы отображать свое недопустимое состояние.

efarley
источник
Ваш бэкэнд на другом порту, чем угловой? Если это так, это может быть проблемой CORS. Какие рамки вы используете для бэкэнда.
Mike3355
Вы можете использовать setErrosметод. Советы: Вы должны добавить необходимый валидатор в ваш файл компонента. Также есть ли конкретная причина использовать ngModel с реактивными формами?
developer033
@ developer033 немного опоздал на вечеринку, но они не похожи на Reactive Form, а на основе шаблонов.
thenetimp

Ответы:

263

в компоненте:

formData.form.controls['email'].setErrors({'incorrect': true});

и в HTML:

<input mdInput placeholder="Email" type="email" name="email" required [(ngModel)]="email"  #email="ngModel">
<div *ngIf="!email.valid">{{email.errors| json}}</div>
Юлия Пассынкова
источник
14
А как вы потом уберете ошибку? setErrors({'incorrect': false})или setErrrors({})не работают на меня
Робуст
3
Могу ли я установить всю реактивную форму как действительную или недействительную вместо сброса полей?
экстремист
29
@Robouste вы можете удалить ошибки вручнуюsetErrrors(null)
Idrees Khan
6
В дополнение к этому ответу: этот код не работает для меня без formData.form.controls['email'].markAsTouched();@ @Farahmand, упомянутого ниже. Используя setErrors({'incorrect': true})просто установить ng-invalidкласс CSS для ввода. Надеюсь, это кому-нибудь поможет.
Барабас
4
А что, если есть больше валидаторов, например «required» - setErrors (null) удаляет эту ошибку?
Please_Dont_Bully_Me_SO_Lords
88

Добавление к ответу Юлии Пассынковой

Чтобы установить ошибку проверки в компоненте:

formData.form.controls['email'].setErrors({'incorrect': true});

Чтобы сбросить ошибку проверки в компоненте:

formData.form.controls['email'].setErrors(null);

Будьте внимательны с удалением ошибок, используя, так nullкак это перезапишет все ошибки. Если вы хотите сохранить некоторые из них, вам, возможно, придется сначала проверить наличие других ошибок:

if (isIncorrectOnlyError){
   formData.form.controls['email'].setErrors(null);
}
Эрик Д.
источник
3
Можно ли сбросить ошибку проверки, используя что-то вроде formData.form.controls ['email']. SetErrors ({'invalid': false});
rudrasiva86
1
А как насчет реактивных форм?
Seidme
26

Я пытался вызвать setErrors()внутри обработчика ngModelChange в форме шаблона. Это не сработало, пока я не подождал один тик с setTimeout():

шаблон:

<input type="password" [(ngModel)]="user.password" class="form-control" 
 id="password" name="password" required (ngModelChange)="checkPasswords()">

<input type="password" [(ngModel)]="pwConfirm" class="form-control"
 id="pwConfirm" name="pwConfirm" required (ngModelChange)="checkPasswords()"
 #pwConfirmModel="ngModel">

<div [hidden]="pwConfirmModel.valid || pwConfirmModel.pristine" class="alert-danger">
   Passwords do not match
</div>

составная часть:

@ViewChild('pwConfirmModel') pwConfirmModel: NgModel;

checkPasswords() {
  if (this.pwConfirm.length >= this.user.password.length &&
      this.pwConfirm !== this.user.password) {
    console.log('passwords do not match');
    // setErrors() must be called after change detection runs
    setTimeout(() => this.pwConfirmModel.control.setErrors({'nomatch': true}) );
  } else {
    // to clear the error, we don't have to wait
    this.pwConfirmModel.control.setErrors(null);
  }
}

Подобные ошибки заставляют меня предпочитать реактивные формы.

Марк Райкок
источник
Cannot find name 'NgModel'.ошибка в строке @ViewChild('pwConfirmModel') pwConfirmModel: NgModel;любое исправление для этой проблемы
Deep 3015
Что случилось с необходимостью использовать setTimeOuts? Я заметил это так же, как кажется, элементы управления не обновляются сразу. Это вводит много хакерского кода, чтобы обойти это ограничение.
Джейк Шексуорт,
Спасибо. Я знал, setErrorsно это не работало, пока я не использовалsetTimeout
Sampgun
25

В новой версии материала 2, контрольное имя которого начинается с префикса mat, setErrors () не работает, вместо этого ответ Джуйлы можно изменить на:

formData.form.controls['email'].markAsTouched();
M_Farahmand
источник
1

Вот пример, который работает:

MatchPassword(AC: FormControl) {
  let dataForm = AC.parent;
  if(!dataForm) return null;

  var newPasswordRepeat = dataForm.get('newPasswordRepeat');
  let password = dataForm.get('newPassword').value;
  let confirmPassword = newPasswordRepeat.value;

  if(password != confirmPassword) {
    /* for newPasswordRepeat from current field "newPassword" */
    dataForm.controls["newPasswordRepeat"].setErrors( {MatchPassword: true} );
    if( newPasswordRepeat == AC ) {
      /* for current field "newPasswordRepeat" */
      return {newPasswordRepeat: {MatchPassword: true} };
    }
  } else {
    dataForm.controls["newPasswordRepeat"].setErrors( null );
  }
  return null;
}

createForm() {
  this.dataForm = this.fb.group({
    password: [ "", Validators.required ],
    newPassword: [ "", [ Validators.required, Validators.minLength(6), this.MatchPassword] ],
    newPasswordRepeat: [ "", [Validators.required, this.MatchPassword] ]
  });
}
Роман Нет
источник
Это может быть "хакерским", но мне это нравится, потому что вам не нужно настраивать собственный ErrorStateMatcher для работы с ошибками ввода углового материала!
Дэвид Мелин
1

В моей Реактивной форме мне нужно было пометить поле как недействительное, если было проверено другое поле. В версии 7 я сделал следующее:

    const checkboxField = this.form.get('<name of field>');
    const dropDownField = this.form.get('<name of field>');

    this.checkboxField$ = checkboxField.valueChanges
        .subscribe((checked: boolean) => {
            if(checked) {
                dropDownField.setValidators(Validators.required);
                dropDownField.setErrors({ required: true });
                dropDownField.markAsDirty();
            } else {
                dropDownField.clearValidators();
                dropDownField.markAsPristine();
            }
        });

Итак, выше, когда я отмечаю флажок, он устанавливает раскрывающийся список по мере необходимости и помечает его как грязный. Если вы не пометите его как таковой, он не будет недействительным (по ошибке), пока вы не попытаетесь отправить форму или взаимодействовать с ней.

Если для флажка установлено значение false (не отмечено), мы очищаем требуемый валидатор в раскрывающемся списке и возвращаем его в исходное состояние.

Также - не забудьте отписаться от мониторинга полей изменений!

Katana24
источник
1

Вы также можете изменить viewChild 'type' на NgForm следующим образом:

@ViewChild('loginForm') loginForm: NgForm;

А затем ссылаться на ваши элементы управления так же, как упоминала @Julia:

 private login(formData: any): void {
    this.authService.login(formData).subscribe(res => {
      alert(`Congrats, you have logged in. We don't have anywhere to send you right now though, but congrats regardless!`);
    }, error => {
      this.loginFailed = true; // This displays the error message, I don't really like this, but that's another issue.

      this.loginForm.controls['email'].setErrors({ 'incorrect': true});
      this.loginForm.controls['password'].setErrors({ 'incorrect': true});
    });
  }

Установка ошибок в null очистит ошибки в пользовательском интерфейсе:

this.loginForm.controls['email'].setErrors(null);
Жак
источник
0

Хотя его поздно, но следующее решение работало от меня.

    let control = this.registerForm.controls['controlName'];
    control.setErrors({backend: {someProp: "Invalid Data"}});
    let message = control.errors['backend'].someProp;
Дила Гурунг
источник
-9

Для модульного теста:

spyOn(component.form, 'valid').and.returnValue(true);
Ванг Бом
источник