Premium support for our pure JavaScript UI components


Post by Josh Argent »

Hi,

We are getting an error in the console when deleting rows at the top and bottom of a large dataset in a tree grid.

Using the "Tree Grid demo" we are generating a large amount of tree data using the following snippet:

const data = [];

for (let i = 0; i < 50; i++) {
  const parent = new Gate({name: 'Parent', children: []});
  for (let j = 0; j < 50; j++) {
    const child = new Gate({name: 'Child', children: []});
    parent.appendChild(child);
    for (let k = 0; k < 50; k++) {
      const grandchild = new Gate({name: 'Grandchild'});
      child.appendChild(grandchild);
    }
  }
  data.push(parent);
}

The reproduction steps are:

  1. Expand all rows in the grid
  2. Select the top parent row and the bottom child (total 2 rows selected)
  3. Call tree.store.remove(tree.selectedRecords) to remove the selected rows

You get the following error in the console:

Uncaught TypeError: Cannot read properties of undefined (reading 'id')
    at RowManager.getOffsetHeight (grid.module.js?458960:53:9633)
    at RowManager.calculateTop (grid.module.js?458960:53:10497)
    at RowManager.correctError (grid.module.js?458960:53:17756)
    at RowManager.updateRenderedRows (grid.module.js?458960:53:17291)
    at TreeGrid.<anonymous> (grid.module.js?458960:53:131872)
    at TreeGrid.<anonymous> (grid.module.js?458960:10:241253)
    at grid.module.js?458960:10:240747

Post by alex.l »

Tested that in latest released version, no errors here. What version do you use? Could you please try to replicate that in our online example? https://bryntum.com/examples/grid/tree/

All the best,
Alex


Post by Josh Argent »

This is reproducible in the tree grid demo on 5.0.4. I modified the example code to generate a large volume of data and include a "Delete Selected" button:

import { TreeGrid, GridRowModel } from '../../build/grid.module.js?458960';
import shared from '../_shared/shared.module.js?458960';

class Gate extends GridRowModel {
    static get fields() {
        return [{
            name : 'capacity',
            type : 'number'
        }, 'domestic', 'airline', 'manager'];
    }
}

Gate.exposeProperties();

// Transform a parent node to a leaf node when all its children are removed
Gate.convertEmptyParentToLeaf = true;

const data = [];

for (let i = 0; i < 50; i++) {
  const parent = new Gate({name: 'Parent', children: []});
  for (let j = 0; j < 50; j++) {
    const child = new Gate({name: 'Child', children: []});
    parent.appendChild(child);
    for (let k = 0; k < 50; k++) {
      const grandchild = new Gate({name: 'Grandchild'});
      child.appendChild(grandchild);
    }
  }
  data.push(parent);
}


let tree = new TreeGrid({

appendTo : 'container',

features : {
    cellEdit   : true,
    filter     : true,
    rowReorder : true,
    stripe     : true
},

loadMask : 'Loading tree data...',

columns : [
    { text : 'Id', field : 'id', width : 40, editor : false },
    { text : 'ParentIndex', field : 'parentIndex', width : 40, hidden : true },
    {
        text        : 'Name',
        field       : 'name',
        flex        : 3,
        type        : 'tree',
        touchConfig : { editor : false }
        // You can customize expand/collapse icons
        // expandIconCls   : 'b-fa b-fa-plus-square',
        // collapseIconCls : 'b-fa b-fa-minus-square'
    },
    { type : 'aggregate', text : 'Capacity', field : 'capacity', flex : 1 },
    { text : 'Domestic', field : 'domestic', flex : 1 },
    { text : 'Airline', field : 'airline', flex : 1 },
    { text : 'Responsible<br/>Manager', field : 'manager', width : 100, htmlEncodeHeaderText : false }
],

store : {
    modelClass : Gate,
    data: data
},

tbar : [
    {
        type        : 'button',
        ref         : 'customButton',
        icon        : 'b-fa-folder-open',
        pressedIcon : 'b-fa-plane',
        text        : 'Use custom tree icons',
        toggleable  : true,
        onToggle({ pressed }) {
            tree.store.readUrl = 'data/' + (pressed ? 'ohare-airport.json' : 'kastrup-airport.json');
            tree.element.classList[pressed ? 'add' : 'remove']('ohare-airport');
            tree.store.load();
        }
    },
    {
        type     : 'button',
        ref      : 'expandAllButton',
        icon     : 'b-fa b-fa-angle-double-down',
        text     : 'Expand all',
        onAction : () => tree.expandAll()
    },
    {
        type     : 'button',
        ref      : 'collapseAllButton',
        icon     : 'b-fa b-fa-angle-double-up',
        text     : 'Collapse all',
        onAction : () => tree.collapseAll()
    },
    {
        type     : 'button',
        ref      : 'deleteButton',
        text     : 'Delete Selected',
        onAction : () => tree.store.remove(tree.selectedRecords) 
    }
]
});

I have also recorded a video of the exact reproduction steps: https://drive.google.com/file/d/18mOKDE0mEzFy00-C6inFCUJjLcSj3oCf/view?usp=sharing


Post by alex.l »

Now I see the error, thank you for the test case! Here is a ticket: https://github.com/bryntum/support/issues/4656

All the best,
Alex


Post by Josh Argent »

Thanks Alex!


Post Reply