Reputation: 331
I have a reactive form and I want to change password and confirm password validators
when I change the password value. I´m subscribing to password control valueChanges
and setting the validators
when the control value changes. To avoid repeating the operation just once, I unsubscribed after setting validators
.
The problem is that the validators are set correctly but once all fields get completed, although there is no error in the form, but it is marked as invalid
.
I have tried setting the validators
outside the subscription to the valueChanges
and it works properly.
I tried using a function that returns the controls that have errors but no error was returned once I completed all fields as expected.
I don´t know why it doesn't work properly.
Form code:
this.form = this.fb.group({
usuario: [this.data.usuario, [Validators.required]],
password: [this.data.password, [Validators.required, Validators.minLength(6)]],
confirmarPassword: [{ value: '', disabled: true }],
nombre: [this.data.nombre, [Validators.required]],
apellido: [this.data.apellido, [Validators.required]],
inicial: [this.data.inicial, [Validators.required]],
email: [this.data.email, [Validators.required, Validators.email]],
habilitado: [this.data.habilitado.value],
imagenPerfil: [this.data.imagenPerfil, null],
modoNuevoPerfil: [false],
modoEditarPerfil: [false],
permisos: this.fb.group({
nombre: ['', null],
usuarios: this.fb.group({
alta: [false],
baja: [false],
modificacion: [false],
visualizacion: [false]
}),
usuariosPerfiles: this.fb.group({
alta: [false],
baja: [false],
modificacion: [false],
visualizacion: [false]
}),
configuracionesTecnicas: this.fb.group({
alta: [false],
baja: [false],
modificacion: [false],
visualizacion: [false]
}),
drogas: this.fb.group({
alta: [false],
baja: [false],
modificacion: [false],
visualizacion: [false]
}),
drogasCertificados: this.fb.group({
alta: [false],
baja: [false],
visualizacion: [false]
}),
drogasRetesteos: this.fb.group({
alta: [false],
baja: [false],
modificacion: [false],
aprobarRechazar: [false],
visualizacion: [false]
}),
drogasMovimientos: this.fb.group({
alta: [false],
baja: [false],
modificacion: [false],
visualizacion: [false]
}),
soluciones: this.fb.group({
alta: [false],
baja: [false],
modificacion: [false],
aprobarRechazar: [false],
visualizacion: [false]
}),
equiposAuxiliares: this.fb.group({
alta: [false],
baja: [false],
modificacion: [false],
visualizacion: [false]
}),
equiposAuxiliaresCertificados: this.fb.group({
alta: [false],
baja: [false],
modificacion: [false],
visualizacion: [false]
}),
materialVolumetrico: this.fb.group({
alta: [false],
baja: [false],
modificacion: [false],
visualizacion: [false]
}),
materialVolumetricoCertificados: this.fb.group({
alta: [false],
baja: [false],
modificacion: [false],
visualizacion: [false]
}),
})
});
Value changes subscription code:
this.passwordChange$ = this.form.controls.usuario.valueChanges.subscribe(
() => {
this.form.setValidators(this.passwordCoinciden('password', 'confirmarPassword'));
this.form.controls.confirmarPassword.enable()
this.form.controls.confirmarPassword.setValidators([Validators.required]);
this.form.updateValueAndValidity()
this.passwordChange$.unsubscribe()
}
)
Function to check errors code:
function findInvalidControls() {
const invalid = [];
const controls = this.form.controls;
for (const name in controls) {
if (controls[name].invalid) {
invalid.push(name);
}
}
return invalid;
}
Upvotes: 0
Views: 8969
Reputation: 1452
here is a working example.
export class AppComponent implements OnInit {
loginForm: FormGroup = this.fb.group({
phonenumber: [""],
check: [false]
});
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.loginForm.get("check").valueChanges.subscribe(value => {
if (value) {
this.loginForm.get("phonenumber").setValidators([Validators.required]);
} else {
this.loginForm.get("phonenumber").clearValidators();
}
this.loginForm.get("phonenumber").updateValueAndValidity({ emitEvent : false });
console.log(this.loginForm.valid);
});
}
loginUser() {}
}
you can test it here
For those who get an error saying "MaxExecutionStack..." be aware, that this is because
emitEvent : false
option inside updateValueAndValidity
method!
Upvotes: 0
Reputation: 331
I have found a way to solve this, i do not understand why it works this why but still this could help some one.
Set my cumstom validator when the form is initialized but keep my confirmarPassword
disabled so the validation is not checked.
Then I subscribe to this.form.controls.password.valueChanges
and when it changes i enable confirmarPassword
So as I said i do not know why but the the form validators do not work as expected if you set them inside a formControl valueChanges observable.
Form Code:
this.form = this.fb.group({
usuario: [this.data.usuario, [Validators.required]],
password: [this.data.password, [Validators.required, Validators.minLength(6)]],
confirmarPassword: [{ value: '', disabled: true }],
nombre: [this.data.nombre, [Validators.required]],
apellido: [this.data.apellido, [Validators.required]],
inicial: [this.data.inicial, [Validators.required]],
email: [this.data.email, [Validators.required, Validators.email]],
habilitado: [this.data.habilitado.value],
imagenPerfil: [this.data.imagenPerfil, null],
modoNuevoPerfil: [false],
modoEditarPerfil: [false],
});
// Here I set the validator but it does not work until I enable 'confirmarPassword'
this.form.setValidators(this.passwordCoinciden('password', 'confirmarPassword'));
Value Changes Subscription Code:
this.passwordChange$ = this.form.controls.usuario.valueChanges.subscribe(
() => {
this.form.controls.confirmarPassword.setValidators([Validators.required]);
this.form.controls.confirmarPassword.enable()
this.form.updateValueAndValidity()
this.passwordChange$.unsubscribe();
}
)
UPDATE 9/7/2020
I found that the problem was in my custom validator i was using incorrectly the ValidatorFn interfase because i was returning an empty object when there was no error instead of null.
MODIFIED CUSTOM VALIDATOR CODE
passwordCoinciden(_password: string, _confirmarPassword: string) : ValidatorFn{
return (group: FormGroup): {[key: string]: any} => {
let password = group.controls[_password];
let confirmarPassword = group.controls[_confirmarPassword];
if (password.value && confirmarPassword.value && password.value != confirmarPassword.value ) {
this.form.controls[_confirmarPassword].markAllAsTouched()
this.form.controls[_confirmarPassword].setErrors({passNoCoinciden: "Los passwords no coinciden" })
return {passNoCoinciden: "Los passwords no coinciden" }
} else {
this.form.controls[_confirmarPassword].setErrors(null);
return null
}
}
}
Upvotes: 0
Reputation: 297
I wrote a post regarding RF and custom validator functions, you can find some examples
https://dev.to/salimchemes/reactiveforms-formarrays-and-custom-validators-1d0k
Upvotes: 1