【问题标题】:How do I disable child component (child formgroup)?如何禁用子组件(子表单组)?
【发布时间】:2021-09-22 18:40:01
【问题描述】:

我有:

  • 主要组件(也是主要的formGoup)- register-form
  • 子组件(也是子 formGoup)- 行

您可以看到我的主表单(没有子表单)处于禁用状态,您可以通过单击编辑按钮启用它。我也希望子组件是这样的。因此,整个表单被禁用,并且在单击编辑按钮时它被启用(您可以键入、选择等)。我该怎么做? 我试过做这样的事情:

  constructor(private formBuilder: FormBuilder) {
    this.registerForm = this.formBuilder.group({
      username: [{value: '', disabled: this.disableForm}],
      email: [{value: '', disabled: this.disableForm}],
      password: [{value: '', disabled: this.disableForm}],
      confirmpassword: [{value: '', disabled: this.disableForm}],
      dropdown: [{value: '', disabled: this.disableForm}],
      checkbox1: [{value: '', disabled: this.disableForm}],
      rowForm: this.formBuilder.group(
        {
          input1: [''],
          input2: [''],
          input3: [''],
          checkbox2: [''] 
        }
      )
    });
  }

但它根本不起作用。

我的注册表单(主组件,主表单组)html文件:

<div class="main-wrapper" fxLayout="row" fxLayoutAlign="center center">
    <mat-card class="box">
        <mat-card-header class="header">
            <mat-card-title>Register</mat-card-title>
        </mat-card-header>

        <form [formGroup]="registerForm" (ngSubmit)="onSubmit()">

            <mat-checkbox class="example-margin" [formControl]="checkbox1">Show hidden option!</mat-checkbox>

            <!-- Username -->
            <mat-card-content>
                <mat-form-field class="example-full-width">
                    <input matInput placeholder="Username" name="username" minlength="5"
                        formControlName="username" required>
                </mat-form-field>
                <mat-error *ngIf="username.touched && !username.valid">
                    <div *ngIf="username.errors?.required">Username is required.</div>
                    <div *ngIf="username.errors?.minlength">Username should be minimum 5 characters.</div>
                </mat-error>

                <!-- Email -->
                <mat-form-field class="example-full-width">
                    <input matInput placeholder="Email"  name="email" minlength="5" [pattern]="emailPattern"
                        formControlName="email" required>
                </mat-form-field>
                <mat-error *ngIf="email.touched && !email.valid">
                    <div *ngIf="email.errors?.required">Email is required.</div>
                    <div *ngIf="email.errors?.pattern">Email is not valid.</div>
                </mat-error>

                <!-- Password -->
                <mat-form-field class="example-full-width">
                    <input matInput placeholder="Password"  name="password" minlength="5"
                        formControlName="password" required>
                </mat-form-field>
                <mat-error *ngIf="password.touched && !password.valid">
                    <div *ngIf="password.errors?.required">Password is required.</div>
                    <div *ngIf="password.errors?.minlength">Password should be minimum 5 characters.</div>
                </mat-error>

                <!-- Repeat Password -->
                <mat-form-field class="example-full-width">
                    <input matInput placeholder="Confirm Password" name="confirmpassword" formControlName="confirmpassword"
                        required>
                </mat-form-field>
                <mat-error *ngIf="confirmpassword.touched && confirmpassword.value != password.value"> Passwords does not match
                </mat-error>


            </mat-card-content> 

            <app-row [rowForm]="registerForm.controls.rowForm"></app-row>

            <button mat-button color="primary" class="btn-block" *ngIf="isEditable; else edit" type="submit"
                [disabled]="!registerForm.valid"> Register
            </button>

            <ng-template #edit>
                <button mat-button color="primary" class="btn-block" type="button" (click)="enableEdit()">
                    Edit
                </button>
            </ng-template>

        </form>
    </mat-card>

我的 register-form (main component, main formgroup) ts文件:

import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';

@Component({
  selector: 'app-register-form',
  templateUrl: './register-form.component.html',
  styleUrls: ['./register-form.component.css']
})
export class RegisterFormComponent implements OnInit {

  emailPattern = '^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$'; 
  registerForm;
  disableForm = true;
  isEditable;

  constructor(private formBuilder: FormBuilder) {
    this.registerForm = this.formBuilder.group({
      username: [{value: '', disabled: this.disableForm}],
      email: [{value: '', disabled: this.disableForm}],
      password: [{value: '', disabled: this.disableForm}],
      confirmpassword: [{value: '', disabled: this.disableForm}],
      checkbox1: [{value: '', disabled: this.disableForm}],
      rowForm: this.formBuilder.group(
        {
          input1: [{value: '', disabled: this.disableForm}],
          input2: [{value: '', disabled: this.disableForm}],
          input3: [{value: '', disabled: this.disableForm}],
          checkbox2: [{value: '', disabled: this.disableForm}] 
        }
      )
    });
  }


  ngOnInit(): void {
  }

  enableEdit() {
    this.disableForm = !this.disableForm;
    this.registerForm.enable();
    this.isEditable = true;
  }


  get username() {
    return this.registerForm.get('username');
  }

  get email() {
    return this.registerForm.get('email');
  }

  get password() {
    return this.registerForm.get('password');
  }

  get confirmpassword() {
    return this.registerForm.get('confirmpassword');
  }



  get checkbox1() {
    return this.registerForm.get('checkbox1');
  }


  onSubmit() {
    console.log(this.registerForm.value);
    this.registerForm.disable();
    this.isEditable = false;
  }
}

我的行(子组件,子表单组)html文件:

<form [formGroup]="rowForm">
  <div formArrayName="rows">
    <div *ngFor="let rows of getControls(); let i=index"  [formGroupName]="i">

      <mat-checkbox class="example-margin" formControlName="checkbox2"  name="checkbox2" (click)="toggleInput()">Show hidden option!</mat-checkbox>

      <mat-form-field class="example-full-width">
        <input matInput placeholder="Input1" formControlName="input1"  name="input1" required>
      </mat-form-field>

      <mat-form-field class="example-full-width">
        <input matInput placeholder="Input2" formControlName="input2"  name="input2" required>
      </mat-form-field>

      <mat-form-field *ngIf="showInput"  class="example-full-width">
        <input matInput placeholder="Input3" formControlName="input3"  name="input3" required>
      </mat-form-field>

      <button mat-button color="primary" *ngIf="rowForm.controls.rows.controls.length > 1" (click)="deleteRow(i)" class="btn btn-danger">Delete Button</button>
    </div>
  </div>
  
  <button mat-button color="primary" (click)="addNewRow()" class="btn btn-primary">Add new Row</button><br>

</form>

我的行(子组件,子formgroup)ts文件:

import {Component, Input, OnInit} from '@angular/core';
import { FormBuilder, FormGroup, FormControl, Validators, FormArray} from '@angular/forms';

@Component({
  selector: 'app-row',
  templateUrl: './row.component.html',
  styleUrls: ['./row.component.css']
})
export class RowComponent implements OnInit {

  @Input() rowForm: FormGroup;
  showInput = false;


  constructor(private formBuilder: FormBuilder) {}


  ngOnInit() {
    this.rowForm = this.formBuilder.group({
      rows: this.formBuilder.array([this.createRow()])
    });
  }


  createRow(): FormGroup {
    return this.formBuilder.group({
      input1: ['', Validators.required],
      input2: ['', Validators.required],
      input3: ['', Validators.required],
      checkbox2: ['', Validators.required],
    });
  }

  toggleInput(index: number) {
    this.showInput = !this.showInput;
  }

  get formArray() {
    return this.rowForm.get('rows') as FormArray;
  }

  // Adding row function
  addNewRow() {
    this.formArray.push(this.createRow());
  }

  deleteRow(index: number) {
    this.formArray.removeAt(index);
  }

  getControls() {
    return (this.rowForm.get('rows') as FormArray).controls;
  }

}

【问题讨论】:

    标签: angular


    【解决方案1】:

    它有点旧,但我喜欢禁用 FormControl using a directive

    否则,您可以创建一个禁用/启用 formGroup 及其子项的函数

      enable(form: FormGroup, enable: boolean) {
        Object.keys(form.controls).forEach(key => {
          const control = form.get(key);
          if (control) {
            if ((control as any).controls)
              this.enable(control as FormGroup, enable);
            else {
              if (enable) control.enable();
              else control.disable();
            }
          }
        });
      }
    

    使用指令将指令添加到每个输入并使用变量,例如

    <input matInput [enableControl]="toogle" placeholder="Ex. Pizza" formControlName="prop1">
    

    每次更改指令时,都会禁用/启用输入

    该功能在您的 .ts 中,只需在您的“编辑”按钮中

    <button (click)="enable(registerForm,true)">Edit</button>
    

    但是您的代码中有一些错误。管理嵌套表单有多种方法。

    1.- 更简单的方法是在父级中创建表单并将“formGroup”传递给子级。但你做错了。创建 registerForm 时需要更改

    this.registerForm = this.formBuilder.group({
      username: [{value: '', disabled: this.disableForm}],
      email: [{value: '', disabled: this.disableForm}],
      password: [{value: '', disabled: this.disableForm}],
      confirmpassword: [{value: '', disabled: this.disableForm}],
      checkbox1: [{value: '', disabled: this.disableForm}],
      rowForm: this.formBuilder.group({
        rows:this.formBuilder.array([this.createRow(true)])
      })
    });
    
      createRow(disabled:boolean=false): FormGroup {
        return this.formBuilder.group({
          input1: [{value:'',disabled:disabled}, Validators.required],
          input2: [{value:'',disabled:disabled}, Validators.required],
          input3: [{value:'',disabled:disabled}, Validators.required],
          checkbox2: [{value:'',disabled:disabled}, Validators.requiredTrue],
        });
      }
    

    看到你在 formArray 中创建元素的重复代码 - 你的孩子中有另一个类似的 - 我更改了一些函数来创建禁用的控件。

    2.-创建一个空的 FromGroup 并在 child 中添加 formGroup。为此,我们将表单组“rowForm”创建为 FromGroup 空

    this.registerForm = this.formBuilder.group({
      username: [{value: '', disabled: this.disableForm}],
      ....
      rowForm: this.formBuilder.group({})
    });
    

    在孩子中,我们在 ngOnInit 中“更改”了这个 formGroup。我附上了一个 setTimeout() 以避免错误“ExpressionChangedAfterItHasBeenCheckedError”

      ngOnInit() {
        setTimeout(()=>{
          this.rowForm.addControl("rows",this.formBuilder.array([this.createRow(true)]))
    
        })
      }
    

    使用这种方法,您无需重复代码

    这样就可以使用我在代码中写的函数enable了。

    this stackblitz 中有第一个选项(在父级中创建整个表单)

    this stackbliz中是第二个(在child中创建rowForm并添加到parent)

    (*)为避免重复代码,您可以使用 ViewChild 来获取子项并使用子项的函数“createRow”

    【讨论】:

    • 在我的代码中会是什么样子?我应该把它放在哪里,下一步该怎么做?对不起,愚蠢的问题,但我只是一个初学者:D
    • @JustABeginner,我用两个方法做了两个stackblitz,希望对你有帮助
    猜你喜欢
    • 1970-01-01
    • 2019-01-03
    • 2016-08-21
    • 2023-04-06
    • 1970-01-01
    • 2016-06-25
    • 2020-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多