Search code examples
angularrowkendo-grid

Angular KendoGrid RowReorderable, drop doesn't work on newly added rows


I have a KendoGrid with a datasource, where i've added a rowreorder-column and i've put the rowReorderable=true.

When the grid is loaded i can drag and drop these rows to change the order. But when i've dynamically added some rows i can't drop on these rowindexes. Only on the first 4 rows because they were already there.

Here's a simple stackblitz example where i've replicated the issue:

https://stackblitz.com/edit/angular-5b3vsr?file=src%2Fapp%2Fapp.component.ts

The fix for the simulation appeared to be this.gridData = [...this.gridData, ...samplecustomers]

But in my main project this fix doesn't seem to resolve the issue. My code for this project:

 openTagSelectionPopup() {
    this.popupService.showEntitySelectionPopup<BaseTag>({
        title: this.translate.get('i18n:LABEL.TAG_SELECTION'),
        entitySet: 'UserBaseTags',
        singleEntitySet: 'BaseTags',
        includes: 'Asset.AssetType,MeasurementUnit.Measurement',
        sort: [{ field: 'Asset.Path', dir: 'asc' }, { field: 'Name', dir: 'asc' }],
        multiSelect: true,
        selectionRequired: false,
        columns: [
            { field: 'Asset.Path', title: this.translate.get('i18n:TAG.ASSET'), filterable: true },
            { field: 'Name', title: this.translate.get('i18n:TAG.NAME'), filterable: true },
            { field: 'MeasurementUnit.Name', title: this.translate.get('i18n:TAG.MEASUREMENT_UNIT'), filterable: true },
            { field: 'MeasurementUnit.Symbol', title: this.translate.get('i18n:TAG.MEASUREMENT_UNIT.SYMBOL'), filterable: true }
        ]
    }).subscribe({
        next: result => {
            if (result && result.length) {
                let addedItems: DataSourceProductionConsumptionItemTag[] = [];
                result.forEach((tag: BaseTag) => {
                    if (findIndex(this.items, (item: DataSourceProductionConsumptionItemTag) => item.TagId == tag.Id) == -1) {
                        addedItems.push({
                            TagId: tag.Id,
                            Tag: tag,
                            Category: '',
                            Color: '#000000'
                        });
                    }
                });
                this.items = [...this.items, ...addedItems];
            }
        }
    });
}

        <kendo-grid #itemsGrid [kendoGridBinding]="items" [height]="410"  style="margin-bottom: 16px;" [rowReorderable]="true"
    kendoGridSelectBy="TagId" [(selectedKeys)]="selectedItemKeys" 
    (cellClick)="cellClick($event)" (cellClose)="cellClose($event)">
        <ng-template kendoGridToolbarTemplate>
            <button kendoButton look="outline" (click)="openTagSelectionPopup()">{{ 'i18n:DATASOURCE.TAGS.ADD' |
                translate }}</button>
            <button kendoButton look="outline" [disabled]="selectedItemKeys.length === 0"
                (click)="removeItems()">{{ 'i18n:DATASOURCE.TAGS.REMOVE' | translate }}</button>
            <kendo-formerror *ngIf="hasGridErr()">{{gridErr}}</kendo-formerror>
        </ng-template>
        <kendo-grid-rowreorder-column [width]="40"></kendo-grid-rowreorder-column>

        <kendo-grid-column [title]="translate.get('i18n:DATASOURCE.PRODUCTION_CONSUMPTION.TAG')" [field]="'TagId'">
            <ng-template kendoGridCellTemplate let-dataItem let-rowIndex>
                {{ getTagDescription(dataItem) }}
            </ng-template>
        </kendo-grid-column>
    </kendo-grid>    

But the UI does seem to be loaded correctly after adding some rows.


Solution

  • It seems this error is happening because you are pushing the same array multiple times, remember that arrays are stored by reference in JavaScript, so even though we do [...customers], that creates a new reference for the array, but not the array elements, so what I have done is, when you add the same elements again into the list, I create a new reference for each of the elements in the array, this seems to eliminate the bug, when you push new array element each time into the array it will not cause this issue, just for this scenario you have this issue, due to pushing the same array elements multiple times.

    import { ChangeDetectorRef, Component } from '@angular/core';
    import { GridItem } from '@progress/kendo-angular-grid';
    import { customers, sampleCustomers } from './customers';
    
        @Component({
          selector: 'my-app',
          template: `
            <button kendoButton (click)="addCustomers()">Add</button>
            <button kendoButton (click)="removeCustomers()">Remove</button>
                <kendo-grid
                    [kendoGridBinding]="gridData"
                    [rowReorderable]="true"
                    [height]="420">
                        <kendo-grid-rowreorder-column [width]="40"></kendo-grid-rowreorder-column>
                        <kendo-grid-column field="CompanyName" [width]="260" title="Company Name"></kendo-grid-column>
                        <kendo-grid-column field="ContactName" [width]="180" title="Contact Name"></kendo-grid-column>
                        <kendo-grid-column field="City" [width]="100"></kendo-grid-column>
                        <kendo-grid-column field="ContactTitle" title="Contact Title"></kendo-grid-column>
                </kendo-grid>
            `,
        })
        export class AppComponent {
          constructor(private cdr: ChangeDetectorRef) {}
          public gridData: unknown[] = customers;
        
          addCustomers() {
            this.gridData = [
              ...this.gridData,
              ...sampleCustomers.map((x) => ({ ...x })),
            ];
            this.cdr.detectChanges();
          }
        
          removeCustomers() {
            this.gridData.splice(4, 9);
            this.cdr.detectChanges();
          }
        }
    

    stackblitz