Home > Enterprise >  Nested Reactive Form to count from main Object
Nested Reactive Form to count from main Object

Time:02-15

I want to create a nested form from Data:

My Actual Data is:

mainObject = {
  adminname: 'Saqib',
  adminemail: '[email protected]',
  users: [
    { user_type: 'Adult', count: 3 },
    { user_type: 'Child', count: 1 },
    { user_type: 'infant', count: 0 },
  ],
};

I want to show nested forms for these Counts in Users Array. like there should be 3 adult forms, 1 child form and no Infant form as infant count is 0. And these counts can be changed like there could be 0 child and 1 infant.

.html

<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
  <input formControlName="name" placeholder="Enter Admin Name" />
  <br />
  <input formControlName="admin_email" placeholder="Enter Admin Email" />

  <div formArrayName="users">
    <div *ngFor="let pro of myForm.get('users').controls; let i = index">
      <br />
      <div [formGroupName]="i" style="border: 1px solid; padding: 10px">
        <div>User Type: {{ pro.value.user_type }}</div>
        User Name:<br />
        <input type="text" formControlName="user_name" /> <br />

        Email:<br />
        <input type="text" formControlName="user_email" />
      </div>
    </div>
  </div>
  
  <p>
    <button type="submit">Submit</button>
  </p>
</form>

.ts

myForm: FormGroup;

  mainObject = {
    adminname: 'Saqib',
    adminemail: '[email protected]',
    users: [
      { user_type: 'Adult', count: 3 },
      { user_type: 'Child', count: 1 },
      { user_type: 'infant', count: 0 },
    ],
  };
  // I want to Show forms according to this users count with their Type:
  // according to this data there should be 3 adult forms, 1 hchild form and no infant Form.

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.formInit();
  }

  formInit() {
    this.myForm = this.fb.group({
      name: '',
      admin_email: '',
      users: this.fb.array(
        this.mainObject.users.map((e) => this.newUsers(e.user_type, e.count))
      ),
    });
  }

  get users(): FormArray {
    return this.myForm.get('users') as FormArray;
  }

  newUsers(t, c): FormGroup {
    console.log(t, c);
    return this.fb.group({
      user_type: t,
      user_name: '',
      user_email: '',
    });
  }

  onSubmit() {
    console.log(this.myForm.value);
  }

I have create example Stackblitz for better understanding:

Example Stackblitz

CodePudding user response:

Perhaps you can achieve the concept as below:

Concept:

  1. Create a dictionary with group by key: user_type and value: an Array with (number of) object(s) created based on count.

  2. Get the value from result 1, perform flatten nested array and add those objects into an array.

toFormUsers(users: any[]): any[] {
  // Generate array by user_type   
  let userTypeGroup = users.reduce((accumulator, current) => {
    accumulator[current.user_type] = accumulator[current.user_type] || [];

    for (let i = 0; i < current.count; i  )
      accumulator[current.user_type].push({ user_type: current.user_type });

    return accumulator;
  }, {});

   // Flatten array of array for userTypeGroup
  return [].concat(
    ...Object.keys(userTypeGroup).map((x) => userTypeGroup[x])
  );
}

And modify your FormGroup to apply the method above by passing mainObject.users.

this.myForm = this.fb.group({
  name: '',
  admin_email: '',
  users: this.fb.array(
    this.toFormUsers(this.mainObject.users).map((e) => this.newUsers(e.user_type, e.count))
  ),
});

Sample Demo on StackBlitz

CodePudding user response:

To create Nested array of Count in users array from mainObject:

.ts

ngOnInit() {
    this.formInit();
  }

  formInit() {
    this.myForm = this.fb.group({
      name: '',
      admin_email: '',
      users: this.fb.array([]),
    });

    this.mainObject.users.map((e) => {
      if (e.count > 0) {
        for (let i = 0; i < e.count; i  ) {
          this.addUser(e.user_type);
        }
      }
    });
  }

  addUser(t) {
    const userArray = <FormArray>this.myForm.controls['users'];
    const newUser = this.initUser(t);
    userArray.push(newUser);
  }

  initUser(t) {
    return this.fb.group({
      user_type: t,
      user_name: '',
      user_email: '',
    });
  }

  get users(): FormArray {
    return this.myForm.get('users') as FormArray;
  }

  newUsers(t, c): FormGroup {
    console.log(t, c);
    return this.fb.group({
      user_type: t,
      user_name: '',
      user_email: '',
    });
  }
  • Related