实现 Angular 跨域验证的最佳方式

问题描述 投票:0回答:3

我正在尝试找出在 Angular 中实现跨域验证的最佳方法。

例如,我有一个选择字段,使另一个字段成为必填字段。

我希望能够:

  • 如果无效则更改字段边框颜色
  • 每当该字段成为必填项时,都会在该字段前面显示一个 *
  • 显示具体的错误消息,解释哪些验证规则被破坏。

到目前为止,我想出了三种解决方案,但对我来说不太有说服力。

  • 监听选择字段的更改并更新第二个字段的验证器。
  • 监听两个字段的变化并手动执行setErrors
  • 将验证提升到 formGroup(这可能会感觉非常麻烦,因为验证状态现在存储在 formGroup 中,并且不能直接在 formControl 中使用)。

这是一个 Stackblitz 实现,演示了我的调查。

angular angular-reactive-forms
3个回答
17
投票

更新 - 另一种方法 看到这个SO

更新 - 更好的方法

在表单上创建

customValidator
并使用验证器将
setError
用于所需的控件。使用
setError
,让 Angular 为我们添加
ng-invalid
,并且我们不需要订阅值更改。参见:

form: FormGroup = new FormGroup(
  {
    input1: new FormControl('optional'),
    input2: new FormControl(null),
  },
  { validators: this.customValidatorForm() },
);

customValidatorForm() {
  return (form: FormGroup) => {
    const error =
      form.get('input1').value != 'optional' && !form.get('input2').value
        ? { required: true }
        : null;
    form.get('input2').setErrors(error); //<--see the setErrors
    return error;
  };
}

参见stackblitz

旧答案

只需使用

customValidator
,例如:

form: FormGroup = new FormGroup({
  input1: new FormControl('optional'),
  input2: new FormControl(null, this.customValidator()),
});

customValidator() {
  return (control: any) => {
    if (!control.parent) return null;

    let mandatory = control.parent.get('input1').value;
    return mandatory != 'optional' && !control.value ? { required: true } : null;
  };
}

不要求

control.parent
的另一种选择是使用
.bind(this)
。这允许我们在验证器内部访问组件的所有变量,当然还可以访问
this.form
:

form: FormGroup = new FormGroup({
  input1: new FormControl('optional'),
  input2: new FormControl(null, this.customValidator().bind(this)), //<--bind(this)
});

customValidatorBind() {
  return (control: any) => {
    if (!this.form) return null;

    let mandatory = this.form.get('input1').value;
    return mandatory != 'optional' && !control.value ? { required: true } : null;
  };
}

好吧,正如我们希望的那样,当更改

input1
input2
被选中时,您需要使用,在创建表单后订阅
valueChanges
:

this.form.get('input1').valueChanges.subscribe(() => {
  this.form.get('input2').updateValueAndValidity();
});

3
投票

对于跨字段验证,您可以使用

required
验证
@rxweb/reactive-form-validation

您只需在 formControl 中提及

conditionalExpression
,如下所示:

input2:['', RxwebValidators.required({conditionalExpression:'x => x.input1 == "mandatory"' })]

并像这样在你的app.component.ts中设置错误消息

ngOnInit(){
    ReactiveFormConfig.set({"validationMessage":{"required":"This field is required"}});
  }

这是完整的组件代码:

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from "@angular/forms"
import { RxwebValidators } from '@rxweb/reactive-form-validators';

@Component({
    selector: 'app-required-conditionalExpression-validator',
    templateUrl: './required-conditional-expression.component.html'
})
export class RequiredConditionalExpressionValidatorComponent implements OnInit {
    userFormGroup: FormGroup

    constructor(
        private formBuilder: FormBuilder )
    { }

    ngOnInit() {
        this.userFormGroup = this.formBuilder.group({
            input1:[''], 
            input2:['', RxwebValidators.required({conditionalExpression:'x => x.input1 == "mandatory"' })], 
        });
    }
}

这是您的完整 HTML 代码:

<div>
    <form [formGroup]="userFormGroup">

        <div>
            <label>Mandatory/Optional </label>
        <select formControlName="input1">
          <option value="optional">Optional</option>
          <option value="mandatory">Mandatory</option>
        </select>
      <br/><br/>
    </div>
    <div>
      <label>Input2</label>
      <input type="text" formControlName="input2"/><br/>
      <span>
        {{userFormGroup.controls.input2.errors?.required?.message}}
      </span>
    </div>
  </form>
</div>

这是工作示例


2
投票

基于此评论的“更好的方法”:https://stackoverflow.com/a/57123631/8126632

我会以这种方式编辑它,以防止任何其他验证被覆盖:

input2: new FormControl('', [Validators.minLength(4)]),

form.get('input2').setErrors({...error, ...(form.get('input2').errors)});

否则就是一个完美的答案。

© www.soinside.com 2019 - 2024. All rights reserved.