Подтвердить что ты не робот

Angular2 - проверка правильности FormControl при размытии

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

validEmail(c: Control){
if(!c.value.match('[a-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&\'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?')){
  return {
    validEmail: true
  };
}
return null;
}    

ctrlEmailAddress: Control = new Control('', Validators.compose([
Validators.required, this.validEmail]));

Мне было интересно, можно ли активировать проверку на размытие поля, например, в angularJS с:

ng-model-options="{ updateOn: 'blur' }"

Мне известно о параметре blur в поле ввода внутри html, но это не поместит мой элемент управления в заблуждение, если нет способа поместить элемент управления в состояние ошибки.

Может ли кто-нибудь помочь мне в правильном направлении?

Спасибо.

Изменить: Я ищу решение angular2, а не решение с угловым расположением.

4b9b3361

Ответ 1

РЕДАКТИРОВАТЬ 2

Как говорит Алекс и официальная документация, в Angular версии 5.0.0 появилась новая опция для вашего обновления updateOn: 'blur'

this.email = new FormControl(null, {
   validators: Validators.required,
   updateOn: 'blur'
});

Также вы можете использовать другие варианты обновления: change (по умолчанию), blur, submit.


оригинал

Я использую директиву, где удаляю всю проверку на фокусе и возвращаю ее обратно после события размытия. Это основано на ответе Кристиана Дешама.

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

По некоторым причинам порядок очистки имеет смысл, поэтому сначала я очищаю асинхронные валидаторы.

Любое предоставленное предложение будет полезно =)

import { Directive } from '@angular/core';
import { NgControl } from '@angular/forms';

@Directive({
  selector: '[validate-onblur]',
  host: {
    '(focus)': 'onFocus($event)',
    '(blur)': 'onBlur($event)'
  }
})
export class ValidateOnBlurDirective {
    private validators: any;
    private asyncValidators: any;
    constructor(public formControl: NgControl) {
    }
    onFocus($event) {
      this.validators = this.formControl.control.validator;
      this.asyncValidators = this.formControl.control.asyncValidator;
      this.formControl.control.clearAsyncValidators();
      this.formControl.control.clearValidators();
    }

    onBlur($event) {
      this.formControl.control.setAsyncValidators(this.asyncValidators);
      this.formControl.control.setValidators(this.validators);
      this.formControl.control.updateValueAndValidity();
    }
}

Также, пожалуйста, следите за обновлениями в этой теме о Angular 2 о валидации onBlur.


РЕДАКТИРОВАТЬ 1

Есть еще одна проблема - если я просто нажму на поле и после щелчка прочь - будет вызвана проверка. Если у вас есть какое-либо уведомление об этом (или звонки с сервера) - оно будет появляться каждый раз, когда вы это делаете. Таким образом, вы можете добавить свойство wasChanged и использовать его следующим образом:

    @Directive({
        selector: '[validate-onblur]',
        host: {
            '(focus)': 'onFocus($event)',
            '(blur)': 'onBlur($event)',
            '(keyup)': 'onKeyup($event)',
            '(change)': 'onChange($event)',
            '(ngModelChange)': 'onNgModelChange($event)'
        }
    })
    export class ValidationOnBlurDirective {
        private validators: any;
        private asyncValidators: any;
        private wasChanged: any;
        constructor(public formControl: NgControl) {
        }
        onFocus($event) {
            this.wasChanged = false;
            this.validators = this.formControl.control.validator;
            this.asyncValidators = this.formControl.control.asyncValidator;
            this.formControl.control.clearAsyncValidators();
            this.formControl.control.clearValidators();
        }
        onKeyup($event) {
            this.wasChanged = true; // keyboard change
        }
        onChange($event) {
            this.wasChanged = true; // copypaste change
        }
        onNgModelChange($event) {
            this.wasChanged = true; // ng-value change
        }
        onBlur($event) {
            this.formControl.control.setAsyncValidators(this.asyncValidators);
            this.formControl.control.setValidators(this.validators);
            if (this.wasChanged)
                this.formControl.control.updateValueAndValidity();
        }
    }

Ответ 2

Начиная с Angular v 5.0.0 это теперь возможно, пометив updateOn: 'blur' для updateOn: 'blur' управления формы.

Это также означает, что valueChanges не valueChanges этого valueChanges управления формы, пока не произойдет событие размытия. Вот пример с минимальной minlength вместе с required:

this.form = new FormGroup({
  username: new FormControl('', {
  validators: [Validators.required, Validators.minLength(6)], updateOn: 'blur'} )
})

get username() {
  return this.form.get('username');
}

В шаблоне вы хотите отметить, что сообщение проверки не будет отображаться, если к полю не touched:

<div *ngIf="username.hasError('minlength') || username.hasError('required') 
              && username.touched">Required and minlength 6!
</div>

DEMO

PS При необходимости вы также можете отметить это на всей форме, а не только на конкретном элементе управления формы

Ответ 3

Найден способ, в rc6.

1- Создать директиву: validate-onblur.directive.ts

@Directive({
  selector: '[validate-onblur]',
  host: {
    '(focus)': 'onFocus($event)',
    '(blur)': 'onBlur($event)'
  }
})
export class ValidateOnBlurDirective {
    constructor(public formControl: NgControl) {
    }

    onFocus($event) {
      this.formControl.control.markAsUntouched(false);
    }

    onBlur($event) {
      this.formControl.control.markAsTouched(true);
    }
}

Затем в вашем html-шаблоне просто добавьте директиву в вашу форму, в моем примере используйте модель ReactiveFormsModule.

Затем добавьте это в сообщение об ошибке:

<input type="text" formControlName="full_name" validate-onblur />

<span *ngIf="formAccountDetails.controls.full_name.touched && !formAccountDetails.controls.full_name.valid && !formAccountDetails.controls.full_name.pristine" class="errors">
        ...
</span>

Ответ 4

Что-то вроде этого:  Использовать свойство коснулось объекта ngControl.

 <div class="form-group" [class.has-error]="!name.valid && name.touched">
        <label for="name">Name</label>
        <input #name="ngForm" ngControl="name" name="name" type="text" class="form-control" required>
 </div>

Ответ 5

Я немного улучшил решение Alex Shestakov, которое уже было выполнено, чтобы избежать установки состояния управления, когда его значение изменяется, когда он сохраняет фокус.

@Directive({
    selector: '[validate-onblur]',
    host: {
        '(focus)': 'onFocus($event)',
        '(blur)' : 'onBlur($event)'
    }
})
export class ValidateOnBlurDirective {

    private validators: any;
    private asyncValidators: any;
    private hasFocus = false;

    constructor(public formControl: NgControl) {
    }

    onFocus($event) {
        this.hasFocus = true;
        this.validators = this.formControl.control.validator;
        this.asyncValidators = this.formControl.control.asyncValidator;
        this.formControl.control.clearAsyncValidators();
        this.formControl.control.clearValidators();
        this.formControl.control.valueChanges
            .filter(() => this.hasFocus)
            .subscribe(() => this.formControl.control.markAsPending());
    }

    onBlur($event) {
        this.hasFocus = false;
        this.formControl.control.setAsyncValidators(this.asyncValidators);
        this.formControl.control.setValidators(this.validators);
        this.formControl.control.updateValueAndValidity();
    }
}

Таким образом, элемент управления останется в состоянии ожидания, пока он удерживает фокус. Это поможет избежать случая, когда элемент управления недействителен, прежде чем он получит фокус, а затем, как только пользователь начнет вводить его, он будет помечен как действительный, прежде чем произойдет событие размытия, когда валидаторы будут снова установлены и действительная действительность контроль должен быть определен.

Ответ 6

Ты можешь

[class.has-error]="!form.controls['ctrlEmailAddress'].valid"

Это добавит класс has-error, как только вы поменяете модель. Таким образом, в основном вам не нужно размыть, чтобы иметь проверку проверки.

Это решило проблему с угловой версией 2.0.0;)