从嵌套类设计嵌套的反应形式

时间:2019-06-19 16:00:27

标签: angular angular-reactive-forms

我有以下课程:

class License {
   name:string;
   .. lots of other fields.
   nameAttributes:NameAttributes[];
}

class nameAttributes:NameAttributes{
   index:number;
   attribute:string;
}

我知道我可以像这样创建表单,但是这需要我手动创建每个字段(控件),并且每次许可证类更改时,我都必须使用新字段来更新类和这个formGroup。

       this.licenseForm = formBuilder.group({
          name:['name value'],
          otherFields:['their values'],
          nameAttributes: this.formBuilder.array([
            this.formBuilder.group({
              index:[1],
              attribute:["attr1"]
            }),
            this.formBuilder.group({
              index:[2],
              attribute:["attr2"]
            })
          ])
      });

如果我可以将许可证类传递到formBuilder中,它会自动创建必要的FormGroups并根据其名称使它们可用,那么我将更喜欢,因此以下内容将创建两个组,一个“ license”组和一个嵌套的“ nameAttributes”组,其中包含所有与license和nameAttributes相关的控件。

      this.licenseForm = formBuilder.group({
        license:formBuilder.group(license)
      });

我是否错过了某些东西?或者,如果没有一些严肃的课堂自省代码,这是不可能的吗?

2 个答案:

答案 0 :(得分:1)

如果您的对象有数据,您当然可以做到

看看这个stackblitz

您具有类似

的功能
  createForm(data:any):FormGroup
  {
    const group=new FormGroup({});
    for (let key in data)
    {
      if (Array.isArray(data[key])) //if is an array
      {                             //first create the formArray
        group.addControl(key,new FormArray([this.createForm(data[key][0])]))
        for (let i=1;i<data[key].length;i++)  //after add the rest of the elements
          (group.get(key) as FormArray).push(this.createForm(data[key][i]))
      }
      else
      {
        if (typeof(data[key])=="object") //if is an object we add a formGroup
          group.addControl(key,this.createForm(data[key]))
        else  //add a simple control
          group.addControl(key,new FormControl(data[key]))
      }
    }
    return group
  }

并命名为

this.form=this.createForm(this.obj)

答案 1 :(得分:1)

@cyberthreat,如所保证,这是带有ngx-sub-form的版本。

首先,这是现场演示的链接:https://stackblitz.com/edit/angular-td2iew

现在让我们看看它是如何构建的:

app.component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  public licenseUpdated(license: License): void {
    console.log(JSON.stringify(license, null, 2));
  }
}

app.component.html

<app-license-form (licenseUpdated)="licenseUpdated($event)"></app-license-form>

这里没什么好想的,但是请注意一个事实,我们绝对不在乎如何从该组件中获取许可证数据。我们只想在有更新的情况下得到警告。

license-form.component.ts

@Component({
  selector: 'app-license-form',
  templateUrl: './license-form.component.html',
  styleUrls: ['./license-form.component.css']
})
export class LicenseFormComponent extends NgxRootFormComponent<License> {
  @DataInput()
  @Input('license')
  public dataInput: License | null | undefined;

  @Output('licenseUpdated') public dataOutput: EventEmitter<License> = new EventEmitter();

  protected getFormControls(): Controls<License> {
    return {
      name: new FormControl(null, [Validators.required]),
      nameAttributes: new FormControl(null, [Validators.required]),
    };
  }
}

license-form.component.html

<form [formGroup]="formGroup">
    <div>
        Name<br>
        <input type="text" [formControlName]="formControlNames.name">
  </div>

  <div>
    License attributes<br>
    <app-license-attributes-form [formControlName]="formControlNames.nameAttributes"></app-license-attributes-form>
  </div>

  <button class="save" (click)="manualSave()">Save form</button>
  (look at your console to see when the form is saved!)
</form>

<div class="values">
  Form group values
  <pre>{{ formGroupValues | json }}</pre>
</div>

如果您不熟悉ngx-sub-form,在这里,我邀请您阅读该博客文章:https://dev.to/maxime1992/building-scalable-robust-and-type-safe-forms-with-angular-3nf9和/或该项目的自述文件:https://github.com/cloudnc/ngx-sub-form

这里要注意的重要一点是,我们只关心原始值,其他所有内容都分解为子表单组件!此外,关于表单,所有内容都输入了安全类型(ts html!)。

许可证属性-form.component.ts

interface LicenseAttributesForm {
  attributes: NameAttribute[];
}

@Component({
  selector: 'app-license-attributes-form',
  templateUrl: './license-attributes-form.component.html',
  styleUrls: ['./license-attributes-form.component.css'],
  providers: subformComponentProviders(LicenseAttributesFormComponent)
})
export class LicenseAttributesFormComponent extends NgxSubFormRemapComponent<NameAttribute[], LicenseAttributesForm> {
  protected getFormControls(): Controls<LicenseAttributesForm> {
    return {
      attributes: new FormArray([], [Validators.required]),
    };
  }

  protected transformToFormGroup(obj: NameAttribute[]): LicenseAttributesForm {
    return {
      attributes: obj ? obj : [],
    };
  }

  protected transformFromFormGroup(formValue: LicenseAttributesForm): NameAttribute[] | null {
    return formValue.attributes;
  }

  public addAttribute(): void {
    (this.formGroupControls.attributes as FormArray).push(
      this.createFormArrayControl(
        'attributes',
        {
          index: null,
          attribute: null
        }
      )
    );
  }

  public removeAttribute(index: number): void {
    (this.formGroupControls.attributes as FormArray).removeAt(index);
  }

  public createFormArrayControl(
    key: any,
    value: any,
  ): FormControl {
    return new FormControl(value, [Validators.required]);
  }
}

license-attributes-form.component.html

<div [formGroup]="formGroup">
  <button (click)="addAttribute()">Add an attribute</button>

  <div
    class="attribute"
    formArrayName="attributes"
    *ngFor="let attribute of formGroupControls.attributes.controls; let i = index"
  >
    <app-license-attribute-form [formControl]="attribute"></app-license-attribute-form>

    <button (click)="removeAttribute(i)">Delete</button>
  </div>
</div>

最后是最后一个

许可证属性-form.component.ts

@Component({
  selector: 'app-license-attribute-form',
  templateUrl: './license-attribute-form.component.html',
  styleUrls: ['./license-attribute-form.component.css'],
  providers: subformComponentProviders(LicenseAttributeFormComponent)
})
export class LicenseAttributeFormComponent extends NgxSubFormComponent<NameAttribute> {
  protected getFormControls(): Controls<NameAttribute> {
    return {
      index: new FormControl(null, [Validators.required]),
      attribute: new FormControl(null, [Validators.required]),
    };
  }
}

license-attribute-form.component.html

<form [formGroup]="formGroup">
    <div>
        Index<br>
        <input type="number" [formControlName]="formControlNames.index">
  </div>

  <div>
    Attribute<br>
    <input type="text" [formControlName]="formControlNames.attribute">
  </div>
</form>

我真的鼓励您浏览Stackblitz并进行演示,这将是理解和发现我的想法的更简单方法:)