Validatore Angular2 che si basa su più campi modulo

È ansible creare un validatore che può utilizzare più valori per decidere se il mio campo è valido?

Ad esempio, se il metodo di contatto preferito dal cliente è via e-mail, il campo e-mail dovrebbe essere richiesto.

Grazie.


Aggiornato con codice di esempio …


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

Per reiterare i metodi che altri hanno pubblicato, questo è il modo in cui ho creato i validatori FormGroup che non coinvolgono più gruppi.

Per questo esempio, fornire semplicemente i nomi delle chiavi della password e confirmPassword campi 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')}) 

Affinché i Validators possano utilizzare i parametri, devono restituire una function con un FormGroup o FormControl come parametro. In questo caso, sto convalidando 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 }; } } } 

Tecnicamente, avrei potuto convalidare due valori se conoscessi le loro chiavi, ma preferisco nominare i miei Validators allo stesso modo dell’errore che restituiranno. La funzione potrebbe essere modificata per prendere un terzo parametro che rappresenta il nome della chiave dell’errore restituito.

Aggiornato il 6 dicembre 2016 (v2.2.4)

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

La risposta di Dave è stata molto, molto utile. Tuttavia, una leggera modifica potrebbe aiutare alcune persone.

Nel caso in cui sia necessario aggiungere errori ai campi di Control , è ansible mantenere la costruzione effettiva del modulo e dei validatori:

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

Invece di impostare un errore sul ControlGroup , farlo sul campo attuale come segue:

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

Sto usando Angular 2 RC.5 ma non ho trovato il ControlGroup, basato sulla risposta utile di Dave. Ho trovato che FormGroup funziona invece. Così ho fatto alcuni aggiornamenti minori sui codici di Dave e ho pensato di condividerlo con gli altri.

Nel file del componente, aggiungere un’importazione per FormGroup:

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

Definisci i tuoi input nel caso in cui sia necessario accedere direttamente al controllo del modulo:

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

Nel tuo costruttore, istanzia il tuo modulo:

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

Aggiungi la funzione MatchPasswords nella tua 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}) } } } 

Spero che questo aiuti chi sta usando RC.5. Nota che non ho ancora provato su RC.6.

Quando si implementano i validatori per più campi modulo, è necessario accertarsi che i validatori vengano rivalutati quando ciascun controllo del modulo viene aggiornato. La maggior parte degli esempi non fornisce una soluzione per tale scenario, ma questo è molto importante per la coerenza dei dati e il comportamento corretto.

Si prega di vedere la mia implementazione di un validatore personalizzato per Angular 2, che tiene conto di questo: https://gist.github.com/slavafomin/17ded0e723a7d3216fb3d8bf845c2f30 .

Sto usando otherControl.valueChanges.subscribe() per ascoltare le modifiche in altri controlli e thisControl.updateValueAndValidity() per triggersre un altro giro di convalida quando viene modificato un altro controllo.


Sto copiando un codice qui sotto per riferimento futuro:

match-altri-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

Ecco come puoi usarlo con le forms reattive:

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

I validatori più aggiornati possono essere trovati qui: validatori di moebius-mlm / ng .

Espandere la risposta di matthewdaniel poiché non è esattamente corretta. Ecco alcuni esempi di codice che mostrano come assegnare correttamente un validatore a un 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 }; } }

Ecco un esempio funzionante: http://plnkr.co/edit/Zcbg2T3tOxYmhxs7vaAm?p=preview

Un sacco di scavare nella fonte angular ma ho trovato un modo migliore.

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

Parte HTML per il gruppo di password

 
Passwords must match.

Ecco un’altra opzione che è stato in grado di fornire che non dipende da un ControlGroup intero o secondario ma è legata direttamente a ciascun Control .

Il problema che avevo erano i controlli che dipendevano l’uno dall’altro non erano gerarchicamente insieme, quindi non ero in grado di creare un ControlGroup . Inoltre, il mio CSS è stato impostato affinché ogni controllo potesse sfruttare le classi angolari esistenti per determinare se visualizzare lo stile degli errori, che era più complicato quando si trattava di una convalida di gruppo invece di una convalida specifica del controllo. Non è stato ansible provare se un singolo controllo era valido poiché la convalida era legata al gruppo di controlli e non a ogni singolo controllo.

Nel mio caso volevo il valore di una casella di selezione per determinare se un altro campo sarebbe richiesto o meno.

Questo viene creato utilizzando Form Builder sul componente. Per il modello selezionato invece di legarlo direttamente al valore dell’object di richiesta, l’ho associato a funzioni di get / set che mi consentiranno di gestire gli eventi “on change” per il controllo. Quindi sarò in grado di impostare manualmente la validazione per un altro controllo a seconda della selezione controlla il nuovo valore.

Ecco la porzione di visualizzazione pertinente:

  ...  

La porzione di componente pertinente:

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

Nel mio caso ho sempre avuto una convalida del modello legata al controllo, quindi il validator è sempre impostato su qualcosa, ma penso che puoi impostare il validator su null se non hai alcuna convalida legata al controllo.

AGGIORNAMENTO: Esistono altri metodi per acquisire la modifica del modello come (ngModelChange)=changeFunctionName($event) o la sottoscrizione alle modifiche del valore di controllo utilizzando this.form.controls["employee"].valueChanges.subscribe(data => ...))

Ho provato la maggior parte di queste risposte ma nessuna ha funzionato per me. Ho trovato un esempio funzionante qui https://scotch.io/@ibrahimalsurkhi/match-password-validation-with-angular-2

equalTo cercando anche questo e equalTo finito per usare equalTo dal pacchetto di validazione ng2 ( https://www.npmjs.com/package/ng2-validation )

Ecco un esempio: Template Driven:

  

required error

equalTo error

Modello guidato:

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

Modello:

 

required error

equalTo error

Ecco la mia versione che ho usato per garantire che un’età in un campo sia maggiore o uguale all’età in un altro campo. Sto usando anche i gruppi di moduli, quindi uso la funzione group.get piuttosto che 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 }) } } } 

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

Penso che la tua migliore scommessa, per ora, sia quella di creare un formgroup per mantenere i tuoi controlli. Quando installi il tuo passaggio di controllo nella funzione per convalidarlo. esempio:

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

so che dipende molto dalla versione di angularjs2 in esecuzione. Questo è stato testato contro 2.0.0-alpha.46

Se qualcuno ha una sugestione migliore come scrivere un validatore personalizzato (che potrebbe essere il modo migliore per andare), è il benvenuto.

MODIFICARE

puoi anche usare ControlGroup e validare quel gruppo interamente.

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

Basta modificare i messaggi in base al tuo dominio.

La risposta di Louis Cruz è stata molto utile per me.

Per completare basta aggiungere il resto reset setErrors: return passwordConfirmationInput.setErrors (null);

E tutto funziona bene!

Grazie,

Saluti,

TGA

Suggerirei di utilizzare la libreria ng-form-rules . È una libreria fantastica per creare tutti i diversi tipi di moduli con logica di convalida disaccoppiata dal componente e che può dipendere dalle variazioni di valore di altre aree nel modulo. Hanno una grande documentazione , esempi e un video che mostra molte delle sue funzionalità . Fare una convalida come questa, quello che stai cercando di fare è banale.

Puoi controllare il loro README per alcune informazioni di alto livello e un esempio di base.

Regole di convalida della corrispondenza della password angular 4.

Se hai bisogno di errori nei campi di controllo, puoi farlo.

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

Quindi la tua necessità di dichiarare questo metodo nel metodo del constructor come.

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

Invece di impostare un errore sul ControlGroup, farlo sul campo attuale come segue:

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

Parte HTML per il gruppo di password

 
This Field is Required.
{{ngForm.value.password | json}}
Passwords doesn't match.