Угловой валидатор, который опирается на несколько полей формы

Можно ли создать валидатор, который может использовать несколько значений, чтобы решить, действительно ли мое поле?

например, если предпочтительный контактный метод клиента – по электронной почте, тогда необходимо указать поле электронной почты.

Благодарю.


Обновлен с примером кода …


import {Component, View} from 'angular2/angular2'; import {FormBuilder, Validators, formDirectives, ControlGroup} from 'angular2/forms'; @Component({ selector: 'customer-basic', viewInjector: [FormBuilder] }) @View({ templateUrl: 'app/components/customerBasic/customerBasic.html', directives: [formDirectives] }) export class CustomerBasic { customerForm: ControlGroup; constructor(builder: FormBuilder) { this.customerForm = builder.group({ firstname: [''], lastname: [''], validateZip: ['yes'], zipcode: ['', this.zipCodeValidator] // I only want to validate using the function below if the validateZip control is set to 'yes' }); } zipCodeValidator(control) { if (!control.value.match(/\d\d\d\d\d(-\d\d\d\d)?/)) { return { invalidZipCode: true }; } } } 

Чтобы повторить те методы, которые опубликовали другие, это способ, которым я создавал валидаторы FormGroup которые не include несколько групп.

В этом примере просто confirmPassword ключевые имена полей password и confirmPassword .

 // Example use of FormBuilder, FormGroups, and FormControls this.registrationForm = fb.group({ dob: ['', Validators.required], email: ['', Validators.compose([Validators.required, emailValidator])], password: ['', Validators.required], confirmPassword: ['', Validators.required], firstName: ['', Validators.required], lastName: ['', Validators.required] }, {validator: matchingPasswords('password', 'confirmPassword')}) 

Чтобы Validators могли принимать параметры, им нужно вернуть function с помощью FormGroup или FormControl в качестве параметра. В этом случае я проверяю FormGroup .

 function matchingPasswords(passwordKey: string, confirmPasswordKey: string) { return (group: FormGroup): {[key: string]: any} => { let password = group.controls[passwordKey]; let confirmPassword = group.controls[confirmPasswordKey]; if (password.value !== confirmPassword.value) { return { mismatchedPasswords: true }; } } } 

Технически я мог бы проверить любые два значения, если бы знал их ключи, но я предпочитаю называть мои Validators такими же, как и ошибки, которые они возвратят. Функция может быть изменена, чтобы принять третий параметр, который представляет имя ключа возвращенной ошибки.

Обновлено 6 декабря 2016 года (v2.2.4)

Полный пример: https://embed.plnkr.co/ukwCXm/

Ответ Дэйва был очень, очень полезен. Однако небольшая модификация может помочь некоторым людям.

Если вам нужно добавить ошибки в поля Control , вы можете сохранить фактическое построение формы и валидаторов:

 // Example use of FormBuilder, ControlGroups, and Controls this.registrationForm= fb.group({ dob: ['', Validators.required], email: ['', Validators.compose([Validators.required, emailValidator])], password: ['', Validators.required], confirmPassword: ['', Validators.required], firstName: ['', Validators.required], lastName: ['', Validators.required] }, {validator: matchingPasswords('password', 'confirmPassword')}) 

Вместо того, чтобы устанавливать ошибку в ControlGroup , сделайте это в фактическом поле следующим образом:

 function matchingPasswords(passwordKey: string, passwordConfirmationKey: string) { return (group: ControlGroup) => { let passwordInput = group.controls[passwordKey]; let passwordConfirmationInput = group.controls[passwordConfirmationKey]; if (passwordInput.value !== passwordConfirmationInput.value) { return passwordConfirmationInput.setErrors({notEquivalent: true}) } } } 

Я использую Angular 2 RC.5, но не могу найти ControlGroup на основе полезного ответа от Dave. Я обнаружил, что FormGroup работает. Поэтому я сделал некоторые незначительные обновления кодов Дейва и думал, что поделюсь с другими.

В своем файле компонента добавьте импорт для FormGroup:

 import {FormGroup} from "@angular/forms"; 

Определите свои входы, если вам нужно напрямую получить доступ к элементу управления формой:

 oldPassword = new FormControl("", Validators.required); newPassword = new FormControl("", Validators.required); newPasswordAgain = new FormControl("", Validators.required); 

В своем конструкторе создайте экземпляр формы:

 this.form = fb.group({ "oldPassword": this.oldPassword, "newPassword": this.newPassword, "newPasswordAgain": this.newPasswordAgain }, {validator: this.matchingPasswords('newPassword', 'newPasswordAgain')}); 

Добавьте функцию matchPasswords в свой class:

 matchingPasswords(passwordKey: string, passwordConfirmationKey: string) { return (group: FormGroup) => { let passwordInput = group.controls[passwordKey]; let passwordConfirmationInput = group.controls[passwordConfirmationKey]; if (passwordInput.value !== passwordConfirmationInput.value) { return passwordConfirmationInput.setErrors({notEquivalent: true}) } } } 

Надеюсь, это поможет тем, кто использует RC.5. Обратите внимание, что я еще не тестировал RC.6.

При внедрении валидаторов для нескольких полей формы вам нужно будет убедиться, что валидаторы переоценены при обновлении каждого элемента управления формой. Большинство примеров не обеспечивают решения для такого сценария, но это очень важно для согласованности данных и правильного поведения.

Пожалуйста, ознакомьтесь с моей реализацией специального валидатора для Angular 2, который учитывает это: https://gist.github.com/slavafomin/17ded0e723a7d3216fb3d8bf845c2f30 .

Я использую otherControl.valueChanges.subscribe() для прослушивания изменений в другом элементе управления и thisControl.updateValueAndValidity() для запуска очередного раунда проверки при изменении другого thisControl.updateValueAndValidity() управления.


Я копирую код ниже для дальнейшего использования:

матч-другой-validator.ts

 import {FormControl} from '@angular/forms'; export function matchOtherValidator (otherControlName: string) { let thisControl: FormControl; let otherControl: FormControl; return function matchOtherValidate (control: FormControl) { if (!control.parent) { return null; } // Initializing the validator. if (!thisControl) { thisControl = control; otherControl = control.parent.get(otherControlName) as FormControl; if (!otherControl) { throw new Error('matchOtherValidator(): other control is not found in parent group'); } otherControl.valueChanges.subscribe(() => { thisControl.updateValueAndValidity(); }); } if (!otherControl) { return null; } if (otherControl.value !== thisControl.value) { return { matchOther: true }; } return null; } } 

Применение

Вот как вы можете использовать его с реактивными формами:

 private constructForm () { this.form = this.formBuilder.group({ email: ['', [ Validators.required, Validators.email ]], password: ['', Validators.required], repeatPassword: ['', [ Validators.required, matchOtherValidator('password') ]] }); } 

Более свежие валидаторы можно найти здесь: moebius-mlm / ng-validators .

Чтобы расширить ответ на matthewdaniel, так как это не совсем правильно. Вот пример кода, который показывает, как правильно назначить валидатор для ControlGroup .

 import {Component} from angular2/core import {FormBuilder, Control, ControlGroup, Validators} from 'angular2/common' @Component({ selector: 'my-app', template: ` 



Valid?: {{form.valid}}

{{form.value | json}}

` }) export class App { form: ControlGroup constructor(fb: FormBuilder) { this.form = fb.group({ name: ['', Validators.required], email: ['', Validators.required] matchingPassword: fb.group({ password: ['', Validators.required], confirmPassword: ['', Validators.required] }, {validator: this.areEqual}) }); } areEqual(group: ControlGroup) { let val; let valid = true; for (name in group.controls) { if (val === undefined) { val = group.controls[name].value } else { if (val !== group.controls[name].value) { valid = false; break; } } } if (valid) { return null; } return { areEqual: true }; } }

Вот рабочий пример: http://plnkr.co/edit/Zcbg2T3tOxYmhxs7vaAm?p=preview

Много копания в угловом источнике, но я нашел лучший способ.

 constructor(...) { this.formGroup = builder.group({ first_name: ['', Validators.required], matching_password: builder.group({ password: ['', Validators.required], confirm: ['', Validators.required] }, this.matchPassword) }); // expose easy access to passworGroup to html this.passwordGroup = this.formGroup.controls.matching_password; } matchPassword(group): any { let password = group.controls.password; let confirm = group.controls.confirm; // Don't kick in until user touches both fields if (password.pristine || confirm.pristine) { return null; } // Mark group as touched so we can add invalid class easily group.markAsTouched(); if (password.value === confirm.value) { return null; } return { isValid: false }; } 

Часть HTML для группы паролей

 
Passwords must match.

Вот еще один вариант, который я смог придумать, который не зависит от целой или вспомогательной ControlGroup но привязан непосредственно к каждому ControlGroup Control .

Проблема, с которой я столкнулась, заключалась в том, что элементы управления, зависящие друг от друга, не были иерархически вместе, поэтому я не смог создать ControlGroup . Кроме того, мой CSS был настроен на то, что каждый элемент управления будет использовать существующие угловые classы, чтобы определить, следует ли отображать стилизацию ошибок, что было более сложным при работе с групповой проверкой вместо проверки, специфичной для управления. Попытка определить, действителен ли один элемент управления, невозможен, поскольку проверка была привязана к группе элементов управления, а не к каждому отдельному элементу управления.

В моем случае я хотел, чтобы значение поля выбора определяло, требуется ли другое поле или нет.

Это построено с помощью Form Builder на компоненте. Для выбранной модели вместо прямого связывания ее с значением объекта запроса я связал ее с функциями get / set, которые позволят мне обрабатывать события «on change» для элемента управления. Затем я смогу вручную установить проверку для другого элемента управления в зависимости от выбранного элемента управления новым значением.

Вот соответствующая часть обзора:

  ...  

Соответствующая часть компонента:

 export class RequestComponent { form: ControlGroup; request: RequestItem; constructor(private fb: FormBuilder) { this.form = fb.group({ employee: new Control("", Validators.required), empID: new Control("", Validators.compose([Validators.pattern("[0-9]{7}"])) }); get employeeModel() { return this.request.isEmployee; } set employeeModel(value) { this.request.isEmployee = value; if (value === "Yes") { this.form.controls["empID"].validator = Validators.compose([Validators.pattern("[0-9]{7}"), Validators.required]); this.form.controls["empID"].updateValueAndValidity(); } else { this.form.controls["empID"].validator = Validators.compose([Validators.pattern("[0-9]{7}")]); this.form.controls["empID"].updateValueAndValidity(); } } } 

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

UPDATE: Существуют другие способы захвата изменения модели, такие как (ngModelChange)=changeFunctionName($event) или подписка на изменения контрольных значений с помощью this.form.controls["employee"].valueChanges.subscribe(data => ...))

Я пробовал большинство из этих ответов, но никто из них не работал на меня. Я нашел рабочий пример здесь https://scotch.io/@ibrahimalsurkhi/match-password-validation-with-angular-2

Также искал это и закончил использование equalTo из пакета проверки ng2 ( https://www.npmjs.com/package/ng2-validation )

Вот пример: Шаблон Driven:

  

required error

equalTo error

Модель:

 let password = new FormControl('', Validators.required); let certainPassword = new FormControl('', CustomValidators.equalTo(password)); this.form = new FormGroup({ password: password, certainPassword: certainPassword }); 

Шаблон:

 

required error

equalTo error

Вот моя версия, которую я использовал для обеспечения возраста в одном поле, больше или равно возрасту в другом поле. Я также использую группы форм, поэтому я использую функцию group.get а не group.controls[]

 import { FormGroup } from '@angular/forms'; export function greaterThanOrEqualTo(sourceKey: string, targetKey: string) { return (group: FormGroup) => { let sourceInput = group.get(sourceKey); let targetInput = group.get(targetKey); console.log(sourceInput); console.log(targetInput); if (targetInput.value < sourceInput.value) { return targetInput.setErrors({ notGreaterThanOrEqualTo: true }) } } } 

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

  this.form = this._fb.group({ clientDetails: this._fb.group({ currentAge: ['', [Validators.required, Validators.pattern('^((1[89])|([2-9][0-9])|100)$')]], expectedRetirementAge: ['', [Validators.required]] }), }, { validator: greaterThanOrEqualTo('clientDetails.currentAge', 'clientDetails.expectedRetirementAge') }); 

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

  this.password = new Control('', Validators.required); let x = this.password; this.confirm = new Control('', function(c: Control){ if(typeof c.value === 'undefined' || c.value == "") return {required: "password required"}; if(c.value !== x.value) return {error: "password mismatch"}; return null; }); 

Я знаю, что это сильно зависит от версии angularjs2, в которой вы работаете. Это было протестировано против 2.0.0-alpha.46

Если у кого-то есть лучшее предложение, например, написать специальный валидатор (который может быть лучшим способом), то это приветствуется.

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

вы также можете использовать ControlGroup и полностью проверить эту группу.

 this.formGroup = new ControlGroup({}, function(c: ControlGroup){ var pass: Control = c.controls["password"]; var conf: Control = c.controls["confirm"]; pass.setErrors(null, true); if(pass.value != null && pass.value != ""){ if(conf.value != pass.value){ pass.setErrors({error: "invalid"}, true); return {error: "error"}; } } return null; }); 

Просто отредактируйте сообщения в соответствии с вашим доменом.

Ответ Луи Круза был очень полезен для меня.

Для завершения просто добавьте в else reset setErrors: return passwordConfirmationInput.setErrors (null);

И все работает отлично!

Спасибо вам,

С Уважением,

TGA

Я бы предложил использовать библиотечные ng-form-rules . Это потрясающая библиотека для создания всех различных форм форм с логикой проверки, отделенной от компонента, и которая может зависеть от изменения значений других областей в форме. У них отличная документация , примеры и видео, в которых показана своя функциональность . Выполнение валидации таким образом, что вы пытаетесь сделать, тривиально.

Вы можете проверить их README для получения информации о высоком уровне и базового примера.

Угловые правила проверки правильности пароля.

Если вам нужны поля управления ошибками, вы можете это сделать.

 createForm() { this.ngForm = this.fb.group({ 'first_name': ["", Validators.required ], 'last_name' : ["", Validators.compose([Validators.required, Validators.minLength(3)]) ], 'status' : ['active', Validators.compose([Validators.required])], 'phone':[null], 'gender':['male'], 'address':[''], 'email':['', Validators.compose([ Validators.required, Validators.email])], 'password':['', Validators.compose([Validators.required])], 'confirm_password':['', Validators.compose([Validators.required])] }, {validator: this.matchingPassword('password', 'confirm_password')}); } 

Тогда вам нужно объявить этот метод в методе constructor Like as.

 constructor( private fb: FormBuilder ) { this.createForm(); } 

Вместо того, чтобы устанавливать ошибку в ControlGroup, сделайте это в фактическом поле следующим образом:

  matchingPassword(passwordKey: string, confirmPasswordKey: string) { return (group: FormGroup): {[key: string]: any} => { let password = group.controls[passwordKey]; let confirm_password = group.controls[confirmPasswordKey]; if (password.value !== confirm_password.value) { return { mismatchedPasswords: true }; } } } 

Часть HTML для группы паролей

 
This Field is Required.
{{ngForm.value.password | json}}
Passwords doesn't match.
  • Угловая форма 2 для проверки пароля повторения
  • Как очистить кеш шаблонов?
  • В чем разница между @ViewChild и @ContentChild?
  • Загрузка файлов с помощью API-интерфейса Angular2 в REST
  • Что такое параметр read в @ViewChild для
  • Повторите элемент HTML несколько раз, используя ngFor на основе числа
  • Как передать данные на угловые маршрутизаторы?
  • Угловое изменение на каждом нажатии клавиши
  • Как вызвать rest api при загрузке углового приложения 2
  • Предупреждать пользователя о несохраненных изменениях перед выходом на страницу
  • Страница обновления Angular2 router.navigate обновить
  • Давайте будем гением компьютера.