【问题标题】:Angular 2 form validation on hidden fields隐藏字段上的 Angular 2 表单验证
【发布时间】:2017-06-17 11:12:24
【问题描述】:

我有一个银行贷款申请,其中包含很多输入字段,其中一些是隐藏的(隐藏字段根据一组条件动态显示)。例如,如果您选择选项 1,则会显示一个隐藏字段,并隐藏其他一些字段。如果您选择选项 2,某些字段会显示,其他字段会隐藏。在表单的末尾我有一个这意味着按钮将被禁用,直到整个表单有效,但我现在的问题是隐藏字段也得到验证,因此表单永远不会有效。有没有办法告诉 Angular 不验证字段是否隐藏?

我隐藏字段的方式如下例所示:

<form [formGroup]="form">

<select formControlName="loanType"> 
 <option value="0">Car loan</option>
 <option value="1">Student loan</option>
</select>

<div *ngIf="loanType === 0"> 
 <input type="text" required>
</div>

<div *ngIf="loanType === 1">
 <input type="text" required>
</div>

<button type="submit" [disabled]="!form.isValid">

</form>

【问题讨论】:

  • 您使用哪种表单语法:模板驱动表单还是模型驱动表单?对于模型驱动的表单,我想说在模板中隐藏字段是不够的,您还必须更新模型(在组件类中)。您可以使用AbstractControl.clearValidators() 之类的方法以编程方式清除特定字段的验证器。
  • (旁注:你不只是用*ngIf“隐藏”这些字段,你实际上是从DOM中删除它们。)
  • 看看这个博客:scotch.io/tutorials/…
  • @AngularFrance 他用*ngIf 删除它,是的,所以它不应该以任何方式影响表单!如果是这样就很奇怪。有趣的是,在 Angular 1 中,一个表单是正确的 .$valid,即使带有 ng-show="false"required 输入是空的。
  • @Blauhirn 这是 Angular 2 的响应式表单的记录行为,是预期的,请参阅 Kara 对此问题的回复:github.com/angular/angular/issues/7970

标签: javascript forms validation angular


【解决方案1】:

您正在使用反应形式。即使字段对用户隐藏,字段在 from 中也是活动的。因此,您只需使用以下代码从响应式中禁用该字段

form.get("fieldName").disable();

在反应形式中,您不需要输入标签中的“必需”。还要添加 formControlName,如下所示。

<input formControlName="inputFieldName" type="text">

所以html文件会是这样的

<form [formGroup]="form" novalidate>

<select formControlName="loanType"> 
 <option value="0">Car loan</option>
 <option value="1">Student loan</option>
</select>

<div *ngIf="loanType === 0"> 
 <input formControlName="inputField1" type="text">
</div>

<div *ngIf="loanType === 1">
 <input formControlName="inputField2" type="text">
</div>

<button type="submit" [disabled]="!form.isValid">

</form>

我们将formControlName添加到2个输入字段中,并在ts文件中声明。

this.form = this.formBuilder.group({
    loanType: ["", [Validators.required]],
    inputField1: ["", [Validators.required]],
    inputField2: ["", [Validators.required]],
});

我们可以为loanType字段创建值变化监听器

this.form.get("loanType").valueChanges.subscribe((loanType) => {
    this.form.get("inputField1").disable();
    this.form.get("inputField2").disable();
    if(loanType === 1) {
         this.form.get("inputField1").enable();
    } else if (loanType === 2) {
         this.form.get("inputField2").disable();
    }
});

所以当贷款类型为 1 时 inputField1 将被启用,当贷款类型为 2 时 inputField2 将被启用。

此表单将在字段被隐藏时有效,因为它被禁用。

【讨论】:

  • 我认为如果在必填字段上显示星号 (*) 会更好的用户体验,因此我不会省略这些字段的 required 属性。
  • 这个答案应该是公认的答案,因为当您可以禁用控制器时,删除和添加控制器没有意义。如果需要,您无需考虑稍后再次添加控制器,只需启用它们即可。
  • 注意:每次调用 disable 或 enable 时都会调用 valueChanges。
【解决方案2】:

更新:

经过一番研究,我发现我需要使用 FormGroup.addControl() 和 FormGroup.removeControl() 来动态更新 formGroup。

我阅读的文章得出我的结论是: https://github.com/angular/angular/issues/7970(查看卡拉斯答案)

https://scotch.io/tutorials/how-to-implement-conditional-validation-in-angular-2-model-driven-forms

只是为了给下一个遇到同样问题的人举例说明我的代码是什么样的:

if (this.loanTypeId === 1) {
   this.form.addControl('name', new FormControl("", Validators.required));
} else {
   this.form.removeControl('name')
}

【讨论】:

  • 这个我没试过,但是如果你去掉控制器,以后再添加控制器,之前写的值还能用吗?例如。如果我在name 字段中写“约翰”。当您稍后删除并添加控制器时,名称“John”是否仍然可见?
  • 我可能会沿着编写自定义验证器的路线走下去,它模拟所需的,但需要一个额外的属性,你绑定到它以隐藏。当隐藏为真时,总是返回有效。警惕heroes 自定义验证器示例中的双重否定!
  • 这是我给出的自定义验证器示例,没有混淆。 stackoverflow.com/a/54756903/495157
【解决方案3】:

首先,您可以根据您的选择创建一组模板。 我们可以在模板中使用 *ngIf 来隐藏和显示表单中的一组元素。 然后使用 formBuilder 创建表单的表单实例,每次只传递那些启用的表单控件的对象。

示例

    <form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<label for="name">First Name:</label>
<input type="text" formControlName="fname"
placeholder="Enter name">
<br /><br />
<div *ngIf="lNameEmail1">
<label for="name">Last Name:</label>
<input type="text" formControlName="lname"
placeholder="Enter name">
<br /><br />

<label for="email">Email:</label>
<input type="email" formControlName="email"
placeholder="Enter email">
</div>
<div *ngIf="lNameEmail2">

<label for="name">Last Name2:</label>
<input type="text" formControlName="lname2"
placeholder="Enter name">

<br /><br />

<label for="email">Email2:</label>
<input type="email" formControlName="email2"
placeholder="Enter email">
</div>
<br /><br />
<button type="submit" [disabled]="!myForm.valid">Submit
</button>
<button type="submit" (click)='formGrp1()'> Form 1</button>
<button type="submit" (click)='formGrp2()'> Form 2</button>
</form> 

Angualr类

export class AppComponent implements AfterViewInit {
    public myForm: FormGroup;
    lNameEmail1 = false;
    lNameEmail2 = false;
    myFormProperty1 = {
    "fname": new FormControl("", Validators.required)
    };

    myFormProperty2 = {
    "fname": new FormControl("", Validators.required),
    "lname": new FormControl("", Validators.required),
    "email": new FormControl("")

    };
    myFormProperty3 = {
    "fname": new FormControl("", Validators.required),
    "lname2": new FormControl("", Validators.required),
    "email2": new FormControl("")

    };

    constructor(public fb: FormBuilder) {
    this.myForm = this.fb.group(this.myFormProperty1);
    }


    formGrp1(){
    alert('Form 1 enable')

    this.lNameEmail1 = true;
    this.lNameEmail2 = false;

    this.myForm = this.fb.group(this.myFormProperty2);


    this.myForm.valueChanges.subscribe(data =>
    console.log('form object ====' + JSON.stringify(data)
    )); 
    }
    formGrp2(){
    alert('Form 2 enable')

    this.lNameEmail1 = false;
    this.lNameEmail2 = true;

    this.myForm = this.fb.group(this.myFormProperty3);

    this.myForm.valueChanges.subscribe(data =>
    console.log('form object ====' + JSON.stringify(data)
    )); 

    }
    onSubmit() {
    console.log('Form submitted Value=='+ JSON.stringify(this.myForm.value));
    }



    }

【讨论】:

    猜你喜欢
    • 2012-06-28
    • 1970-01-01
    • 2013-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-29
    • 2015-10-05
    • 2012-12-06
    相关资源
    最近更新 更多