Our blazing fast Grid component built with pure JavaScript


Post by giorgi »

Hi,

I have a web application without any framework, just plain javascript and using Grid.

I need to update grid store dataset completely, but seems like calling
grid.store.data = newData
only works first time. On second and third call, it maintains old originalData in the store and while new data is only added to data property.

Please see attachments:
Attachments
second-update.JPG
second-update.JPG (117.79 KiB) Viewed 4873 times
first-update-data.JPG
first-update-data.JPG (51.82 KiB) Viewed 4873 times
first-update.JPG
first-update.JPG (31.14 KiB) Viewed 4873 times

Post by Maxim Gorkovsky »

Hello.
I don't see it being reflected in the docs, but when you setting data on the store instead of replacing it completely store is synchronizing the data. So in case you already have records with IDs matching IDs in the new dataset, existing records will be updated.

I can suggest clearing store before appending new records: https://www.bryntum.com/docs/gantt/#Core/data/Store#function-removeAll

Post by giorgi »

Hi, thanks for quick reply.

I know that the records are synchronizing, which is a good and intended behavior.

The problem I have is that it does not synchronize the data correctly.

I am fetching new data from server and setting store.data = [newData] and also adding new columns. The grid updates visually, everything looks ok, but when trying to edit it using double-click on the cell, it display's 0, but it should display original value.

Also second problem is that if I have these in features
 
 groupSummary: true,
 summary: true
 
then while adding new data, it throws an error: "Uncaught (in promise) TypeError: Cannot read property 'find' of undefined".

I also tried to synchronize the data myself (add fields to existing data) and set the data to store. It still has these 0s in the editor and displaying 0s in the summary.

P.S.
grid.store.removeAll();
did not work.
Attachments
two-columns.JPG
two-columns.JPG (55.15 KiB) Viewed 4860 times
after.JPG
after.JPG (28.27 KiB) Viewed 4860 times
before.JPG
before.JPG (25.5 KiB) Viewed 4860 times

Post by Maxim Gorkovsky »

Could you provide a simple runnable test case? You can modify one of our demos.

Post by mats »

Just a minor observation:
store.data = [newData] 
If you're doing this and newData is your array, you should instead do:
store.data = newData 

Post by giorgi »

Sure, here it is. Just paste this in your demo editor.

We have two sets of data, one for groupA and the other one groupB. On first add (button click add column), adds first group and on second click, adds second group. On the second click, there is an error in the console and can not add second set of data. But if the table is grouped then it adds new column, but double clicking on cell and trying to edit it, inserts 0. Also summaries are zeros.

Thanks for your help.

P.S. store.data = [newData] this is not an issue :) newData is in square brackets, because I am not exactly using that variable name, its just kind of placeholder :) .
import { Grid, DataGenerator, WidgetHelper } from '../../build/grid.module.js?438972';
import shared from '../_shared/shared.module.js?438972';

let columnsA = [
  {
    text: 'Group A',
    filterable: false,
     children: [
        {
            text: 'weight',
            field: 'group_a_weight',
            width: 80,
            type: 'number',
            hidden: false,
             renderer: ({ value }) => {
                  return roundTo(value * 100, 3);
             },
             summaries: [{
                 sum: 'sum',
                 renderer: ({ sum }) => {
                     return roundTo(sum * 100, 3)
                }
             }]

         },
         {
            text: 'param',
            field: 'group_a_param',
            width: 150,
            hidden: true
         }
     ]
  }
];

let columnsB = [
  {
    text: 'Group B',
    filterable: false,
     children: [
        {
            text: 'weight',
            field: 'group_b_weight',
            width: 80,
            type: 'number',
            hidden: false,
             renderer: ({ value }) => {
                  return roundTo(value * 100, 3);
             },
             summaries: [{
                 sum: 'sum',
                 renderer: ({ sum }) => {
                     return roundTo(sum * 100, 3)
                }
             }]

         },
         {
            text: 'param',
            field: 'group_b_param',
            width: 150,
            hidden: true
         }
     ]
  }
];

let grid = new Grid({
    adopt : 'container',
    minHeight : '20em',
    features : {
        cellEdit: true,
            filter: true,
            columnPicker: true,
            regionResize: true,
            groupSummary: true,
            summary: true

    },

    columns : [
        { text: 'Id', field: 'id', width: 300 },
 
    ],

    store: {
        syncDataOnLoad: true,
        data: []
     }
});

var counter = 0;

WidgetHelper.append([
    {
        type     : 'button',
        ref      : 'addButton',
        text     : 'Add column',
        color    : 'b-orange b-raised',
        icon     : 'b-fa b-fa-plus',
        tooltip  : 'Add new column',
        onAction : async () => {
            if (counter <= 1) {
               var data = await generateData(counter ? 'group_b' : 'group_a', counter ? 15 : 10);
               
               console.log(data);
var columns = counter ? columnsB : columnsA;
             
               grid.store.data = data;
               columns.forEach(d => grid.columns.add(d));
               counter++;
            }
        }
    }], { insertFirst : document.getElementById('tools') || document.body });

function generateData(group, n) {
   return new Promise((resolve, reject) => {
       // simulate async call
       setTimeout(() => {
           var data = [];
           
            for (let i = 0; i < n; i++) {
               var obj = {id: String(i)};

               obj[group + '_weight'] = Math.random()
               obj[group + '_param'] = 'Some String Param'
 

               data.push(obj)
            }

             resolve(data); 
       }, 100)
   })
}

function roundTo(value, decimals) {
  if (value == undefined || value == null) return 0;
  if (value == 0) return 0;
  return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
}

Post by giorgi »

Hi, I have added a video in the zip file.

Can you tell what I am doing wrong? And how to update the grid state correctly on each data update?
Attachments
bryntum-issue.zip
(7.84 MiB) Downloaded 226 times

Post by sergey.maltsev »

Hi, giorgi!

Try this sample code below.

Few tips.

1. Use autoAddField columns config to properly update store fields.
https://www.bryntum.com/docs/grid/#Grid/data/ColumnStore#config-autoAddField

2. Use this approach to add column and set new data.
grid.columns.add(counter === 1 ? columnsB : columnsA);
grid.store.removeAll();
grid.store.add(data);
3. Don't forget to fill all fields for both columns in your generator.
Second run should use both ['group_a', 'group_b'] to create fields.
let columnsA = [
    {
        text       : 'Group A',
        filterable : false,
        children   : [
            {
                text     : 'weight',
                field    : 'group_a_weight',
                width    : 80,
                type     : 'number',
                hidden   : false,
                renderer : ({ value }) => {
                    return roundTo(value * 100, 3);
                },
                summaries : [{
                    sum      : 'sum',
                    renderer : ({ sum }) => {
                        return roundTo(sum * 100, 3);
                    }
                }]

            },
            {
                text   : 'param',
                field  : 'group_a_param',
                width  : 150,
                hidden : true
            }
        ]
    }
];

let columnsB = [
    {
        text       : 'Group B',
        filterable : false,
        children   : [
            {
                text     : 'weight',
                field    : 'group_b_weight',
                width    : 80,
                type     : 'number',
                hidden   : false,
                renderer : ({ value }) => {
                    return roundTo(value * 100, 3);
                },
                summaries : [{
                    sum      : 'sum',
                    renderer : ({ sum }) => {
                        return roundTo(sum * 100, 3);
                    }
                }]

            },
            {
                text   : 'param',
                field  : 'group_b_param',
                width  : 150,
                hidden : true
            }
        ]
    }
];

let grid = new Grid({
    adopt     : 'container',
    minHeight : '20em',
    features  : {
        cellEdit     : true,
        filter       : true,
        columnPicker : true,
        regionResize : true,
        groupSummary : true,
        summary      : true

    },

    columns : {
        autoAddField : true,
        data         : [{ text : 'Id', field : 'id', width : 300 }]

    },

    store : {
        syncDataOnLoad : true,
        data           : []
    }
});

var counter = 0;

WidgetHelper.append([
    {
        type     : 'button',
        ref      : 'addButton',
        text     : 'Add column',
        color    : 'b-orange b-raised',
        icon     : 'b-fa b-fa-plus',
        tooltip  : 'Add new column',
        onAction : async() => {
            if (counter <= 1) {
                const
                    data = await generateData(counter ? ['group_a', 'group_b'] : ['group_a'], counter ? 15 : 10);

                console.log(data);
                grid.columns.add(counter === 1 ? columnsB : columnsA);
                grid.store.removeAll();
                grid.store.add(data);
                counter++;
            }
        }
    }], { insertFirst : document.getElementById('tools') || document.body });

function generateData(groups, n) {
    return new Promise((resolve, reject) => {
        // simulate async call
        setTimeout(() => {
            const
                data = [];

            for (let i = 0; i < n; i++) {
                const
                    obj = { id : String(i) };

                groups.forEach(group => {
                    obj[group + '_weight'] = Math.random();
                    obj[group + '_param'] = 'Some String Param';
                });

                data.push(obj);
            }

            resolve(data);
        }, 100);
    });
}

function roundTo(value, decimals) {
    if (value == null || value === 0) {
        return 0;
    }
    return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
}

Post Reply