简体   繁体   中英

How to reuse FormGroup to fill out same field in different forms in Angular 9?

I am creating a form to capture data from field input in Angular .

Lets say I have (Student, Faculty, Administration) that fills out the form.

They(2 or all) share some fields (birthday, first name, last name) that can be reused and other fields that are different for all (work address, home address, mailing address) and different only for 2(student ID, faculty ID).

Is it possible to have multiple form groups for that purpose? How would I approach this if they each have many fields?

This can be achieved using Model Based Reactive Forms using an intuitive library @rxweb/reactive-form-validators which i found on npm

npm i @rxweb/reactive-form-validators

Start by creating a model class having properties which you need in your formgroup as below

import {  prop, } from "@rxweb/reactive-form-validators"
export class User {

    @prop()
    firstName: string;

    @prop()
    lastName: string;

    @prop()
    emailAddress: string;

}

The @prop() defines a property which can be used to initialize a formControl using the formGroup method of RxFormBuilder . This model can be later in other components to resue these properties and make a formGroup without writing the same code multiple times

import { Component, OnInit } from '@angular/core';
import { FormGroup } from "@angular/forms"

import { RxFormBuilder } from '@rxweb/reactive-form-validators';

import { User } from './user.model';

@Component({
    selector: 'app-user-add',
    templateUrl: './user-add.component.html'
})
export class UserAddComponent implements OnInit {

    userFormGroup: FormGroup

    constructor(
        private formBuilder: RxFormBuilder
    ) { }

    ngOnInit() {
        let user = new User();
        this.userFormGroup = this.formBuilder.formGroup(user);
    }
}

The component Html file is as below:

<form *ngIf="userFormGroup" [formGroup]="userFormGroup">
  <div class="form-group">
    <label>FirstName</label>
    <input type="text" formControlName="firstName" class="form-control" />
  </div>
  <div class="form-group">
    <label>LastName</label>
    <input type="text" formControlName="lastName" class="form-control" />
  </div>
  <div class="form-group">
    <label>Email Address</label>
    <input type="text" formControlName="emailAddress" class="form-control" />
  </div>
  <button [disabled]="!userFormGroup.valid" class="btn btn-primary">
    Submit
  </button>
</form>

Here is the complete example on stackblitz

If you want to extend the class and add extra properties to the formGroup, you can use the class abstraction feature available in the same library, along with this it comes with many inbuilt validators which makes it easy to perform validations

To know more about this approach, please referSimplified Reactive Forms

If you're using reactive forms, it may look tempting but it's kinda easy when you realize that FormGroup is just a JS object. Because of that, you can use them like any other JS object.

The simpler way would be to implement a method that does that in a service, and make use of your JS/TS object knowledge:

private commonFields;
private roleBasedFields;
private addressForm;

constructor() {
  this.commonFields = {
    firstName: '',
    lastName: ['', Validators.required],
    birthday: [null, Validators.required]
  };

  this.addressForm = {
     street: '',
     streetNo: null,
     zip: null,
     city: '',
     // and so on...
  };

  this.roleBasedFields = {
    student: {
      homeAddress: addressForm,
      // add other fields related to student here
    },
    faculty: {
      workAddress: addressForm,
      // add other fields here
    },
    administration: {
      mailingAddress: {
        ...addressForm,
        department: ['', Validators.required]
        // if the address object is different for a certain role, you can add them like this
      },
      // add other fields here
    },
};

}

buildForm(role: 'student' | 'faculty' | 'administration'): FormGroup {
  return new FormGroup({
    ...this.commonFields,
    ...this.roleBasedFields[role]
  });
}

And in the component, depending on how you want it implemented, use it like:

someForm: FormGroup;
formArray: FormArray;

ngOnInit() {
  this.someForm = this.thatServiceAbove.buildForm('student');

  // if it goes in an array
  this.formArray = new FormArray([]);
}

// method to push the FormGroup in a FormArray:
generateForm(role: 'student' | 'faculty' | 'administration') {
   this.formArray.push(this.thatServiceAbove.buildForm(role));
}

You get the idea:D

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM