【问题标题】:Angular reactive form set validators on control change控制更改的角度反应表单集验证器
【发布时间】:2020-12-23 04:51:32
【问题描述】:

我有一个响应式表单,我想在更改密码值时更改 密码确认密码 validators。我订阅密码控制valueChanges 并在控制值更改时设置validators。为了避免重复操作一次,我在设置validators后取消了订阅。

问题是验证器设置正确但是一旦所有字段都完成后,虽然表单没有错误,但它被标记为invalid

我已尝试将订阅之外的validators 设置为valueChanges,它可以正常工作。

我尝试使用一个函数,该函数返回有错误的控件,但在我按预期完成所有字段后没有返回错误。

我不知道为什么它不能正常工作。

表格代码:

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

值变订阅码:

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 findInvalidControls() {
     const invalid = [];
     const controls = this.form.controls;
     for (const name in controls) {
         if (controls[name].invalid) {
             invalid.push(name);
         }
     }
     return invalid;
 }

【问题讨论】:

  • 为什么不忘记删除/添加验证器并使用像confirmarPassword: [value: '', [this.passwordCoinciden('password', 'confirmarPassword'),Validators.required] 这样的验证器。请记住,不检查禁用的 FormControl - 它始终有效-。顺便说一句,禁用comfirmarPassword的目的是什么?
  • 您确定您的表单在第一次更改后仍在监听吗?因为你在最后取消订阅所以它会第一次监听然后停止监听,所以这段代码将永远不会再次执行
  • @Eliseo。此表单位于一个对话框中,当打开该对话框以添加新用户时,它可以正常工作。当我打开它以编辑现有用户时,会加载所有获取的用户数据,但在修改密码之前我不需要验证密码。这就是我禁用confirmarPassword 的原因。 @Lud我已经尝试了两种取消订阅和不取消订阅的方法。取消订阅的想法是,一旦设置了验证器,代码就不会再次执行。

标签: angular validation angular-reactive-forms


【解决方案1】:

这是一个工作示例。

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

你可以测试一下here

对于那些收到“MaxExecutionStack...”错误的人请注意,这是因为

emitEvent : false

updateValueAndValidity 方法中的选项!

【讨论】:

    【解决方案2】:

    我找到了解决这个问题的方法,我不明白为什么它会这样,但这仍然可以帮助一些人。

    在表单初始化时设置我的自定义验证器,但保持我的 confirmarPassword 禁用,以便不检查验证。

    然后我订阅this.form.controls.password.valueChanges,当它发生变化时我启用confirmarPassword

    正如我所说,我不知道为什么,但是如果您将表单验证器设置在 formControl valueChanges observable 中,它们将无法按预期工作。

    表格代码:

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

    值更改订阅代码:

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

    2020 年 9 月 7 日更新

    我发现问题出在我的自定义验证器中,我错误地使用了 ValidatorFn 接口,因为当没有错误而不是 null 时,我返回了一个空对象。

    修改后的自定义验证码

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

    }

    【讨论】:

      【解决方案3】:

      我写了一篇关于 RF 和自定义验证器功能的帖子,您可以找到一些示例

      https://dev.to/salimchemes/reactiveforms-formarrays-and-custom-validators-1d0k

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-04
        • 1970-01-01
        • 2020-01-17
        相关资源
        最近更新 更多