代码之家  ›  专栏  ›  技术社区  ›  iChido

Angular 4反应式表单切换隐藏表单元素的验证

  •  14
  • iChido  · 技术社区  · 6 年前

    我有一个反应式表单,其中加载时不需要字段。如果选择将向formGroup中添加其他表单元素的选项,则新显示的字段都是必需的。 如果昵称字段被隐藏,那么您应该能够提交表单。如果显示昵称,则需要昵称字段,并禁用提交按钮,直到昵称字段已满。 这是我想做的一个例子。

    我的问题是,一旦表单元素显示/隐藏,如何启用/禁用验证?

    应用程序。单元ts

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { FormsModule, ReactiveFormsModule } from '@angular/forms';
    
    import { AppComponent } from './app.component';
    import { HelloComponent } from './hello.component';
    
    @NgModule({
      imports:      [ BrowserModule, FormsModule, ReactiveFormsModule ],
      declarations: [ AppComponent, HelloComponent ],
      bootstrap:    [ AppComponent ]
    })
    export class AppModule { }
    

    应用程序。组成部分ts

    import { Component, OnInit } from '@angular/core';
    import { Validators, FormControl, FormGroup, FormBuilder } from '@angular/forms';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent implements OnInit  {
      name = 'My Reactive Form';
    
      constructor(
        private fb: FormBuilder
      ) {}
    
      myForm: FormGroup;
      showNick: boolean = false;
    
      ngOnInit() {
        this.myForm = this.fb.group({
          'firstName': new FormControl(),
          'nickName': new FormControl('', Validators.required),
          'lastName': new FormControl()
        })
      }
    
      toggleNick() {
        this.showNick = !this.showNick;
      }
    }
    

    应用程序。组成部分html

    <form [formGroup]="myForm">
      <div class="my-box">
        <label>
          First Name
          <input type="text" formControlName="firstName">
        </label>
      </div>
      <div class="my-box nickname">
        Nickname? &nbsp; <a (click)="toggleNick()">yes / no</a>
      </div>
      <div class="my-box" *ngIf="showNick">
        <label>
          Nickname
          <input type="text" formControlName="nickName">
          <span class="validation-message" *ngIf="!myForm.controls['nickName'].valid && myForm.controls['nickName'].dirty">
        This field is invalid
      </span>
        </label>
      </div>
      <div class="my-box">
        <label>
          Last Name
          <input type="text" formControlName="lastName">
        </label>
      </div>
      <button [disabled]="myForm.invalid">Submit</button>
    </form>
    
    4 回复  |  直到 6 年前
        1
  •  23
  •   DeborahK    6 年前

    在我的申请中,我有一个类似的要求。如果用户要求通过短信通知,则需要手机。否则,电话号码是可选的。

    我写了这个方法:

    setNotification(notifyVia: string): void {
        const phoneControl = this.customerForm.get('phone');
        if (notifyVia === 'text') {
            phoneControl.setValidators(Validators.required);
        } else {
            phoneControl.clearValidators();
        }
        phoneControl.updateValueAndValidity();
    }
    

    它是从ngOnInit中的以下代码调用的:

        this.customerForm.get('notification').valueChanges
                         .subscribe(value => this.setNotification(value));
    

    如果用户更改通知字段(单选按钮),它将调用 setNotification 方法传递值。如果该值为“文本通知”,则会将手机的验证设置为必需。

    否则将清除电话字段的验证。

    然后它 必须 呼叫 updateValueAndValidity 使用此新验证更新表单信息。

        2
  •  19
  •   vivekkurien    6 年前

    即使这些字段对用户是隐藏的,但这些字段在被动来源中也是活动的。因此,您只需使用以下代码从反应中禁用字段

    this.myForm.get("nickName").disable();
    

    将函数更改为toggleNick(),如下所示

    toggleNick() {
        this.showNick = !this.showNick;
        if(showNick) {
             this.myForm.get("nickName").enable();
        } else {
             this.myForm.get("nickName").disable();
        }
    }
    
        3
  •  2
  •   andy    6 年前

    我认为最好的方法是让字段成为初始表单的一部分,并进行所有验证,以及在需要以编程方式禁用和启用字段或嵌套表单时。

    示例: https://stackblitz.com/edit/angular-ojebff

    https://stackblitz.com/edit/angular-ojebff?embed=1&file=app/input-errors-example.html

        4
  •  1
  •   Klem231188    5 年前

    如果您有许多复杂表单中的可选字段,我认为这些解决方案不可行。

    我所做的是这样的事情:

    export class MyComponent implements AfterViewChecked {
    
     @ViewChildren(FormControlName) allFormControlInDOM: QueryList<FormControlName>;
    
     // ...
    
      ngAfterViewChecked(): void {
        // We must disable the controls that are not in the DOM
        // If we don't, they are used for validating the form
        if (this.allFormControlInDOM) {
          const controls: { [p: string]: AbstractControl } = this.myForm.controls;
          for (const control in controls) {
            if (controls.hasOwnProperty(control) && controls[control] instanceof FormControl) {
              const found = this.allFormControlInDOM.find((item: FormControlName) => item.name === control);
              if (found) {
                controls[control].enable();
              } else {
                controls[control].disable();
                controls[control].setValue(null);
              }
            }
          }
        }
      }
    
    // ...
    
    }
    

    我希望这能有所帮助:)