validar reactivos formularios formulario con campos angular

reactivos - Validador Angular2 que se basa en mĂșltiples campos de formulario



validar formulario angular 5 (14)

¿Es posible crear un validador que pueda usar múltiples valores para decidir si mi campo es válido?

por ejemplo, si el método de contacto preferido del cliente es por correo electrónico, entonces se debe requerir el campo de correo electrónico.

Gracias.

Actualizado con código de ejemplo ...

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 }; } } }


Al implementar validadores para múltiples campos de formulario, deberá asegurarse de que los validadores se vuelvan a evaluar cuando se actualice cada uno de los controles de formulario. La mayoría de los ejemplos no proporcionan una solución para tal escenario, pero esto es muy importante para la consistencia de los datos y el comportamiento correcto.

Consulte mi implementación de un validador personalizado para Angular 2, que tiene esto en cuenta: https://gist.github.com/slavafomin/17ded0e723a7d3216fb3d8bf845c2f30 .

Estoy usando otherControl.valueChanges.subscribe() para escuchar los cambios en otro control y thisControl.updateValueAndValidity() para activar otra ronda de validación cuando se cambia otro control.

Estoy copiando un código a continuación para referencia futura:

match-other-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; } }

Uso

Así es como puede usarlo con formas reactivas:

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

Más validadores actualizados se pueden encontrar aquí: moebius-mlm/ng-validators .


Aquí está mi versión que usé para asegurar que una edad en un campo sea mayor o igual a la edad en otro campo. También estoy usando grupos de formularios, así que uso la función group.get lugar de 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 }) } } }

Y en el componente:

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'') });


Aquí hay otra opción que pude encontrar que no depende de un ControlGroup completo o secundario, sino que está vinculada directamente a cada Control .

El problema que tuve fue que los controles que dependían unos de otros no estaban jerárquicamente juntos, así que no ControlGroup crear un ControlGroup . Además, mi CSS se configuró para que cada control aprovechara las clases angulares existentes para determinar si mostrar el estilo de error, lo que fue más complicado cuando se trata de una validación de grupo en lugar de una validación específica de control. Intentar determinar si un solo control era válido no fue posible ya que la validación estaba vinculada al grupo de controles y no a cada control individual.

En mi caso, quería un valor de cuadro de selección para determinar si se requeriría otro campo o no.

Esto se crea utilizando el generador de formularios en el componente. Para el modelo seleccionado en lugar de vincularlo directamente al valor del objeto de solicitud, lo he vinculado a obtener / establecer funciones que me permitirán manejar eventos "en cambio" para el control. Entonces podré establecer manualmente la validación para otro control dependiendo del nuevo valor de los controles seleccionados.

Aquí está la porción de vista relevante:

<select [ngFormControl]="form.controls.employee" [(ngModel)]="employeeModel"> <option value="" selected></option> <option value="Yes">Yes</option> <option value="No">No</option> </select> ... <input [ngFormControl]="form.controls.employeeID" type="text" maxlength="255" [(ngModel)]="request.empID" />

La porción componente relevante:

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(); } } }

En mi caso, siempre tuve una validación de patrón vinculada al control, por lo que el validator siempre está configurado en algo, pero creo que puede configurar el validator como nulo si no tiene ninguna validación vinculada al control.

ACTUALIZACIÓN: Existen otros métodos para capturar el cambio de modelo como (ngModelChange)=changeFunctionName($event) o suscribirse para controlar los cambios de valor mediante this.form.controls["employee"].valueChanges.subscribe(data => ...))


Creo que su mejor apuesta, por ahora, es crear un grupo de formularios para mantener sus controles. Cuando crea una instancia de su pase de control en la función para validarlo. ejemplo:

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; });

Sé que esto depende en gran medida de la versión de angularjs2 que esté ejecutando. Esto fue probado contra 2.0.0-alpha.46

Si alguien tiene una mejor sugestión, como escribir un validador personalizado (que puede ser la mejor manera de hacerlo), es bienvenido.

EDITAR

También puede usar ControlGroup y validar ese grupo por completo.

this.formGroup = new ControlGroup({}, function(c: ControlGroup){ var pass: Control = <Control>c.controls["password"]; var conf: Control = <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; });

Simplemente edite los mensajes según su dominio.


Estaba buscando esto también y terminé usando equalTo del paquete de validación ng2 ( npmjs.com/package/ng2-validation )

Aquí hay un ejemplo: Dirigido por plantilla:

<input type="password" ngModel name="password" #password="ngModel" required/> <p *ngIf="password.errors?.required">required error</p> <input type="password" ngModel name="certainPassword" #certainPassword="ngModel" [equalTo]="password"/> <p *ngIf="certainPassword.errors?.equalTo">equalTo error</p>

Modelo conducido:

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

Modelo:

<form [formGroup]="form"> <input type="password" formControlName="password"/> <p *ngIf="form.controls.password.errors?.required">required error</p> <input type="password" formControlName="certainPassword"/> <p *ngIf="form.controls.certainPassword.errors?.equalTo">equalTo error</p> </form>


Estoy usando Angular 2 RC.5 pero no pude encontrar el ControlGroup, basado en la útil respuesta de Dave. Encontré que FormGroup funciona en su lugar. Así que hice algunas actualizaciones menores en los códigos de Dave y pensé en compartirlas con otros.

En su archivo de componente, agregue una importación para FormGroup:

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

Defina sus entradas en caso de que necesite acceder al control de formulario directamente:

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

En tu constructor, crea una instancia de tu formulario:

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

Agregue la función MatchPasswords en su clase:

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}) } } }

Espero que esto ayude a aquellos que usan RC.5. Tenga en cuenta que todavía no he probado en RC.6.



Muchas excavaciones en la fuente angular, pero he encontrado una mejor manera.

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 }; }

Porción HTML para el grupo de contraseñas

<div ng-control-group="matching_password" [class.invalid]="passwordGroup.touched && !passwordGroup.valid"> <div *ng-if="passwordGroup.touched && !passwordGroup.valid">Passwords must match.</div> <div class="form-field"> <label>Password</label> <input type="password" ng-control="password" placeholder="Your password" /> </div> <div class="form-field"> <label>Password Confirmation</label> <input type="password" ng-control="confirm" placeholder="Password Confirmation" /> </div> </div>


Para ampliar la respuesta de matthewdaniel ya que no es exactamente correcta. Aquí hay un código de ejemplo que muestra cómo asignar correctamente un validador a un ControlGroup .

import {Component} from angular2/core import {FormBuilder, Control, ControlGroup, Validators} from ''angular2/common'' @Component({ selector: ''my-app'', template: ` <form [ngFormModel]="form"> <label for="name">Name:</label> <input id="name" type="text" ngControl="name"> <br> <label for="email">Email:</label> <input id="email" type="email" ngControl="email"> <br> <div ngControlGroup="matchingPassword"> <label for="password">Password:</label> <input id="password" type="password" ngControl="password"> <br> <label for="confirmPassword">Confirm Password:</label> <input id="confirmPassword" type="password" ngControl="confirmPassword"> </div> </form> <p>Valid?: {{form.valid}}</p> <pre>{{form.value | json}}</pre> ` }) 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 }; } }

Aquí hay un ejemplo de trabajo: http://plnkr.co/edit/Zcbg2T3tOxYmhxs7vaAm?p=preview


Para reiterar los métodos que otros han publicado, esta es la forma en que he estado creando validadores de FormGroup que no involucran a múltiples grupos.

Para este ejemplo, simplemente proporcione los nombres de clave de la password y confirmPassword campos 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'')})

Para que los Validators tomen parámetros, deben devolver una function con un FormGroup o FormControl como parámetro. En este caso, estoy validando un 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 }; } } }

Técnicamente, podría haber validado cualquiera de los dos valores si supiera sus claves, pero prefiero nombrar a mis Validators del mismo modo que el error que devolverán. La función podría modificarse para tomar un tercer parámetro que represente el nombre clave del error devuelto.

Actualizado el 6 de diciembre de 2016 (v2.2.4)

Ejemplo completo: https://embed.plnkr.co/ukwCXm/


Sugeriría usar la biblioteca ng-form-rules . Es una biblioteca impresionante para crear todos los diferentes tipos de formularios con lógica de validación desacoplada del componente y que puede depender de los cambios de valor de otras áreas en el formulario. Tienen una excelente documentación , examples y un video que muestra muchas de sus funciones . Hacer una validación como esta lo que intentas hacer es trivial.

Puede ng-form-rules para obtener información de alto nivel y un ejemplo básico.


La respuesta de Dave fue muy, muy útil. Sin embargo, una ligera modificación podría ayudar a algunas personas.

En caso de que necesite agregar errores a los campos de Control , puede mantener la construcción real del formulario y los validadores:

// 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'')})

En lugar de establecer un error en el ControlGroup , hágalo en el campo real de la siguiente manera:

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}) } } }


La respuesta de Louis Cruz fue muy útil para mí.

Para completar, simplemente agregue en el resto el restablecimiento setErrors: return passwordConfirmationInput.setErrors (nulo);

¡Y todo funciona bien!

Gracias,

Saludos,

TGA


Angular 4 reglas de validación de coincidencia de contraseña.

Si necesita campos de control de errores, puede hacerlo.

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'')}); }

Entonces su necesidad de declarar este método en el método constructor Like as.

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

En lugar de establecer un error en el ControlGroup, hágalo en el campo real de la siguiente manera:

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 }; } } }

Porción HTML para el grupo de contraseñas

<form [formGroup]="ngForm" (ngSubmit)="ngSubmit()"> <div class="form-group"> <label class="control-label" for="inputBasicPassword"> Password <span class="text-danger">*</span></label> <input type="password" class="form-control" formControlName="password" placeholder="Password" name="password" required> <div class="alert text-danger" *ngIf="!ngForm.controls[''password''].valid && ngForm.controls[''password''].touched">This Field is Required.</div> </div> {{ngForm.value.password | json}} <div class="form-group"> <label class="control-label" for="inputBasicPassword">Confirm Password <span class="text-danger">*</span></label> <input type="password" class="form-control" name="confirm_password" formControlName="confirm_password" placeholder="Confirm Password" match-password="password"> <div class=''alert text-danger'' *ngIf="ngForm.controls.confirm_password.touched && ngForm.hasError(''mismatchedPasswords'')"> Passwords doesn''t match. </div> </div> <button type="submit" [disabled]="!ngForm.valid" class="btn btn-primary ladda-button" data-plugin="ladda" data-style="expand-left" disabled="disabled"><span class="ladda-label"> <i class="fa fa-save"></i> Create an account <span class="ladda-spinner"></span><div class="ladda-progress" style="width: 0px;"></div> </span><span class="ladda-spinner"></span></button> </form>