Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kendo : Insert a FormGroup at a top into a FormArray

Problem Statement :

In below stackblitz demo, I am able to insert the FormGroup dynamically at the starting of the grid on clicking the Add button and triggering the (blur) event from one control to update the value of another control sharing same rowIndex. Now the issue is if i inserted multiple formGroups and trigger on (blur) event on any of the newly added FormGroups it updates the value of other controls as well having different rowIndex.

Steps to reproduce the issue :

  • Open the below demo link.
  • Add multiple rows (2 rows) by clicking on the Add button.
  • Enter the value in name field of the 2nd newly added row and focus out.
  • It updates the age field in both the newly added row instead of only in second one.

Stackblitz Demo : https://stackblitz.com/edit/angular-oitz5j-4uezqr

Requirement :

Tab out on any name field of particular row, Age field on same row should display a random number without impacting other rows.

What i tried so far ?

  • Tried to use Array unshift() method but getting error

    Property 'unshift' does not exist on type 'FormArray'

  • Tried to use FormArray.insert() method.It will work if we want to add a FormGroup at specific index. But it fails to insert multiple FormGroups on the top of FormArray dynamically.

Update : Above issue is working fine without Kendo Grid. Please check the below demo.

Demo : https://stackblitz.com/edit/angular-oitz5j-2a31gs

Related issues in github/stackoverflow :

https://github.com/angular/angular/issues/16322

Angular - Form Array push specific index

Note : If we are going to add the controls at the end of the Grid, it is working like a champ. Please check the below demo which works fine with adding the controls at the last.

Demo : https://stackblitz.com/edit/angular-oitz5j-aszrjq

like image 614
Creative Learner Avatar asked Sep 25 '19 19:09

Creative Learner


2 Answers

For those who wants to insert elements dynamically in FormArray initially then use Insert with index 0.

this.formName.controls.FieldNameArray.insert(0,[...])

https://angular.io/api/forms/FormArray#insert.

like image 186
Afsar Avatar answered Sep 28 '22 03:09

Afsar


Why isn't my code working?

This isn't a Kendo issue at all. Your entire form is already being created every time the view observable is triggered. So when you add a row, you are basically adding to both the items in createForm as well as triggering the view observable (by calling updateGridData), which in turn adds to the items in createForm. Telerik seems to be doing the latter as seen in this example so we don't need to insert into items at all in addNewRow. Instead, just update gridData and then call updateGridData.

Solution

There are just two issues in your code. The first one being in your view subscribe block. The code you are using will basically just push on top of the previous items and not replace them. So we need to reinitialize the items FormArray here.

this.view.subscribe(r => {
    this.createForm.setControl('items', new FormArray([]));

    r.data.forEach((i) => {
        const newRow = new FormGroup({
            name: new FormControl(i.name),
            age: new FormControl(i.age)
        });
        (this.createForm.get("items") as FormArray).push(newRow);
    });
});

You could rewrite this using map like below.

this.view.subscribe(r => {
    this.createForm.setControl('items', new FormArray(r.data.map(item =>
        new FormGroup({
            name: new FormControl(item.name),
            age: new FormControl(item.age),
        })
    )));
});

Now all you need to do is assign gridData when a new row is added. We need to get the data entered by the user from createForm since gridData is not bound anywhere and will not contain the data which is entered by the user. There will be no need to do anything to the form here since the view subscribe block is already taking care of declaring createForm.

addNewRow() {
    const blankRow = {
        name: "",
        age: ""
    };

    this.gridData = [blankRow, ...this.createForm.get('items').value];
    const data: GridDataResult = { data: this.gridData, total: this.gridData.length };
    this.editService.updateGridData(data);
}

The grid should now work.

Forked StackBlitz

Note: The reason why the example where you are pushing a new row to the end of the grid works is that you are only declaring createForm once at the start in ngOnInit. Then you manually update the gridData and insert into items. There's no updateGridData here which triggers view to recreate createForm. If there was, even this wouldn't be working as expected.

like image 33
nash11 Avatar answered Sep 28 '22 04:09

nash11