Unable to update the angular dynamic reactive form controls - Stack Overflow

I am trying to create a dynamic angular reactive form. And able to construct a form fields with the bel

I am trying to create a dynamic angular reactive form. And able to construct a form fields with the below code, but unable to edit the form controls.

export class BillerDetailsConfirmComponent implements OnInit {
  billerForm!: FormGroup;

  constructor(
    private router: Router,
    private dialogService: NbDialogService,
    private fb: FormBuilder,
    private dashboardService: DashboardService,
    private subScriptionService: SubscriptionService,
    private cdr: ChangeDetectorRef
  ) {}

  ngOnInit(): void {
    this.initializeForm();
    this.getCompleteBillerDetails();
  }

  initializeForm(): void {
    this.billerForm = this.fb.group({
      billerDetails: this.fb.array([])
    });
  }

  getCompleteBillerDetails(): void {
    const billersSubscription = this.dashboardService.getAllBBPSBillers().subscribe(
      (respData: any) => {
        if (respData.respCode === '00') {
          console.log('API Response:', respData.response);
          this.populateFormArray(this.billerDetails, respData.response.billerDetails);
         
        }
      },
      (error: any) => {
        console.error('Error fetching biller details:', error);
      }
    );
    this.cdr.detectChanges(); 

    this.subScriptionService.add("billerCategorySubscription", billersSubscription);
  }

  populateFormArray(formArray: FormArray, data: any[]): void {
    formArray.clear();
    data.forEach(item => {
      const formGroup = this.createFormGroup(item);
      formArray.push(formGroup);
    });
    console.log('Form Array:', formArray);
  }

  createFormGroup(item: any): FormGroup {
    const formGroup: { [key: string]: FormControl } = {};

    Object.entries(item).forEach(([key, value]) => {
      if (typeof value !== 'object') {
        formGroup[key] = new FormControl(value ?? ''); // Ensure controls are created and enabled.
      }
    });

    return this.fb.group(formGroup);
  }

  get billerDetails(): FormArray {
    return this.billerForm.get('billerDetails') as FormArray;
  }


  getFormControlKeys(group: AbstractControl): string[] {
    if (group instanceof FormGroup) {
      return Object.keys(group.controls).filter(key =>
        group.get(key) instanceof FormControl
      );
    }
    return [];
  }

  getFieldChunks(keys: string[], size: number): string[][] {
    const result = [];
    for (let i = 0; i < keys.length; i += size) {
      result.push(keys.slice(i, i + size));
    }
    return result;
  }
}

View

 <nb-tab tabTitle="Biller Details">
                        <div class="block-body">
                          <form [formGroup]="billerForm">
                            <div *ngFor="let billerGroup of billerDetails.controls; let i = index" [formGroup]="billerGroup">
                              <ng-container *ngIf="billerGroup?.controls">
                                <ng-container *ngFor="let chunk of getFieldChunks(getFormControlKeys(billerGroup), 3)">
                                  <div class="row mb-4 justify-content-start">
                                    <div class="col-md-4 d-flex flex-column" *ngFor="let key of chunk">
                                      <label class="form-label">{{ key | titlecase }}</label>
                                      <input nbInput class="w-100" [formControlName]="key" placeholder="Enter {{ key }}" fieldSize="large" />
                                    </div>
                                  </div>
                                </ng-container>
                              </ng-container>
                            </div>
                          </form>
                        </div>
                      </nb-tab>

I am trying to create a dynamic angular reactive form. And able to construct a form fields with the below code, but unable to edit the form controls.

export class BillerDetailsConfirmComponent implements OnInit {
  billerForm!: FormGroup;

  constructor(
    private router: Router,
    private dialogService: NbDialogService,
    private fb: FormBuilder,
    private dashboardService: DashboardService,
    private subScriptionService: SubscriptionService,
    private cdr: ChangeDetectorRef
  ) {}

  ngOnInit(): void {
    this.initializeForm();
    this.getCompleteBillerDetails();
  }

  initializeForm(): void {
    this.billerForm = this.fb.group({
      billerDetails: this.fb.array([])
    });
  }

  getCompleteBillerDetails(): void {
    const billersSubscription = this.dashboardService.getAllBBPSBillers().subscribe(
      (respData: any) => {
        if (respData.respCode === '00') {
          console.log('API Response:', respData.response);
          this.populateFormArray(this.billerDetails, respData.response.billerDetails);
         
        }
      },
      (error: any) => {
        console.error('Error fetching biller details:', error);
      }
    );
    this.cdr.detectChanges(); 

    this.subScriptionService.add("billerCategorySubscription", billersSubscription);
  }

  populateFormArray(formArray: FormArray, data: any[]): void {
    formArray.clear();
    data.forEach(item => {
      const formGroup = this.createFormGroup(item);
      formArray.push(formGroup);
    });
    console.log('Form Array:', formArray);
  }

  createFormGroup(item: any): FormGroup {
    const formGroup: { [key: string]: FormControl } = {};

    Object.entries(item).forEach(([key, value]) => {
      if (typeof value !== 'object') {
        formGroup[key] = new FormControl(value ?? ''); // Ensure controls are created and enabled.
      }
    });

    return this.fb.group(formGroup);
  }

  get billerDetails(): FormArray {
    return this.billerForm.get('billerDetails') as FormArray;
  }


  getFormControlKeys(group: AbstractControl): string[] {
    if (group instanceof FormGroup) {
      return Object.keys(group.controls).filter(key =>
        group.get(key) instanceof FormControl
      );
    }
    return [];
  }

  getFieldChunks(keys: string[], size: number): string[][] {
    const result = [];
    for (let i = 0; i < keys.length; i += size) {
      result.push(keys.slice(i, i + size));
    }
    return result;
  }
}

View

 <nb-tab tabTitle="Biller Details">
                        <div class="block-body">
                          <form [formGroup]="billerForm">
                            <div *ngFor="let billerGroup of billerDetails.controls; let i = index" [formGroup]="billerGroup">
                              <ng-container *ngIf="billerGroup?.controls">
                                <ng-container *ngFor="let chunk of getFieldChunks(getFormControlKeys(billerGroup), 3)">
                                  <div class="row mb-4 justify-content-start">
                                    <div class="col-md-4 d-flex flex-column" *ngFor="let key of chunk">
                                      <label class="form-label">{{ key | titlecase }}</label>
                                      <input nbInput class="w-100" [formControlName]="key" placeholder="Enter {{ key }}" fieldSize="large" />
                                    </div>
                                  </div>
                                </ng-container>
                              </ng-container>
                            </div>
                          </form>
                        </div>
                      </nb-tab>
Share Improve this question asked Mar 11 at 15:52 vishnuvishnu 4,59916 gold badges62 silver badges92 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

Let me explain:

  • I reduce the code to get better performance.
  • I hope this help you out to see how it isn't the best way to create it, and why isn't working.

The main reason as you can see with this form code is, when 1 formControlName change needs to recalculate the view again and blocking the UI for the user.

    <form [formGroup]="billerForm">
      <div formArrayName="billerDetails">
        <div *ngFor="let billerGroup of billerDetails.controls; let i = index">
          {{billerGroup.value | json}}
          <div class="row mb-4 justify-content-start">
            <ng-container [formGroupName]="i">
              <div class="col-md-4 d-flex flex-column" 
                   *ngFor="let input of billerGroup.value | keyvalue">
                  <label class="form-label">{{''+input.key|titlecase}}</label>
                  <input [formControlName]="''+input.key" />
              </div>
            </ng-container>
          </div>
        </div>
      </div>
    </form>
  • formArrayName to access array form reference.
  • billerGroup is formControl so we have access to .value
  • [formGroupName]="i" index of formArray.controls
  • | keyvalue angular pipe for get entries key,value
  • ''+input.key lifehack to give always a string.

Solution

Then I realize one thing, why angular needs to recalculate it!? and the reason is we're in a for loop and he don't know about the items!

  • One important thing is when we do *ngFor we should use trackBy, newer version using @for is required. doc trackBy

stackblitz example

<div class="col-md-4 d-flex flex-column" 
     *ngFor="let input of billerGroup.value | keyvalue; trackBy: trackBy">
 trackBy(index: number) {
    return index;
  }

now any item has reference and can update formControl!

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744783501a4593481.html

相关推荐

  • Unable to update the angular dynamic reactive form controls - Stack Overflow

    I am trying to create a dynamic angular reactive form. And able to construct a form fields with the bel

    11小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信