Our blazing fast Grid component built with pure JavaScript


Post by thomas_e »

We use Bryntum Grid with Vue3 and Vite.
The grid is configured as :

const store = new AjaxStore({
    id: 'storeAllgemein',
    modelClass: WorktimesheetViewAllgemeinModel,
    readUrl: `${API_BASE_URL}/read/view/an/allgemein/`,
    autoLoad: true,
    tree: true,
    lazyLoad: { chunkSize: 1000 }, 
    filterParamName: 'anfilter',
    encodeFilterParams: encodeFilterParams,
});

We have added click-handler on each row triggering backend actions with complex business logic updating rows within the currently open sub-node of our tree-store.

In order to reflect the updates of the backend business logic we want to refresh the content of the currently open sub-node. We do this by calling:

const row = gridConfig.value.store.getById(worktimesheetId);
// worktimeSheetId is the store's id of a row within the sub-node
const parent = row.parent;
parent.clearChildren(true);
gridConfig.value.store.loadChildren(parent);

So far all is fine. Works perfectly.
However we also provide a form input field in our UI where a user can enter a search word (newValue) which updates the complete tree grid by calling:

store.filter({
	property: 'nodeLabel',
	value: newValue,
	disabled: false
});

Before we had introduced our sub-tree-refresh feature (as described above) filtering worked perfectly.
But now the respective sub-node for which we had called clearChildren / loadChildren is "damaged".

  • clicking on the arrow to open such a sub-node no longer opens such a sub-node

  • after clicking on the arrow we observe store.isLoading = true

  • We see the exceptions below

Exceptions we had seen (==> shows the line throwing error):

 @bryntum_grid.js?v=27d563a1:29290 Uncaught TypeError: Cannot read properties of undefined (reading 'includes')
    at AjaxStore.onNodeRemoveChild (@bryntum_grid.js?v=27d563a1:29290:29)
    at @bryntum_grid.js?v=27d563a1:18242:19
    at Array.forEach (<anonymous>)
    at ModelClass.clearChildren (@bryntum_grid.js?v=27d563a1:18240:16)
    at AjaxStore.clear (@bryntum_grid.js?v=27d563a1:24885:25)
    at DynamicTreeStoreLazyLoadPlugin.clearLoaded (@bryntum_grid.js?v=27d563a1:33448:12)
    at DynamicTreeStoreLazyLoadPlugin.load (@bryntum_grid.js?v=27d563a1:33693:12)
    at gridUtils.js:139:36

onNodeRemoveChild(parent, children, index, flags = { isMove: false, silent: false, unfiltered: false }) {
  const me = this, { storage } = me, toRemoveFromUI = [], toRemove = [], { isMove, silent, unfiltered } = flags, removeUnfiltered = unfiltered && me.isFiltered, childrenToRemove = removeUnfiltered && parent.unfilteredChildren ? parent.unfilteredChildren : children;
  me.collectDescendants(childrenToRemove, toRemoveFromUI, toRemove, { inCollapsedBranch: !(parent.isExpanded(me) && parent.ancestorsExpanded(me)), unfiltered: removeUnfiltered });
  if (!isMove) {
    for (const record of children) {
      record.unjoinStore(me);
    }
    for (const record of toRemove) {
==>          if (record.stores.includes(me)) {
            record.unjoinStore(me);
          }
          if (me.added.includes(record)) {
            me.added.remove(record);
          } else if (!record.isLinked) {
            me.removed.add(record);
          }
        }
        me.modified.remove(toRemove);
      }
      if (toRemoveFromUI.length) {
@bryntum_grid.js?v=27d563a1:100893 Uncaught TypeError: Cannot read properties of null (reading 'record')
    at Tree.onElementClick (@bryntum_grid.js?v=27d563a1:100893:34)
    at functionChainRunner (@bryntum_grid.js?v=27d563a1:12579:23)
    at plugInto.<computed> [as onElementClick] (@bryntum_grid.js?v=27d563a1:12555:43)
    at Grid.onHandleElementClick (@bryntum_grid.js?v=27d563a1:107170:14)
    at Grid.onHandleElementClick (@bryntum_grid.js?v=27d563a1:108869:13)
    at Grid.handleEvent (@bryntum_grid.js?v=27d563a1:107003:55)
    at HTMLDivElement.handler (@bryntum_grid.js?v=27d563a1:8131:72)

  /**
   * Called when user clicks somewhere in the grid. Expand/collapse node on icon click.
   * @private
   */
  onElementClick(event) {
    const me = this, target = event.target, cellData = me.client.getCellDataFromEvent(event), clickedExpander = target.closest(".b-tree-expander");
    if (clickedExpander) {
      event.preventDefault();
    }
    if (clickedExpander || me.expandOnCellClick && (cellData == null ? void 0 : cellData.record.isParent)) {
==>      me.toggleCollapse(cellData.record);
    }
  }

Post by ghulam.ghous »

Hey there,

I need to understand what you are doing, so in actual you have some changes on the backend, and you want to fetch them on the frontend, right? Are you using loadOnDemand feature? Also I don't believe using the clearChildren is a right choice here. I would say please use https://bryntum.com/products/grid/docs/api/Core/data/mixin/TreeNode#function-replaceChildren to add the new children. Does it help?

Also it would be great if you can provide a small runnable test case which we can debug.


Post by thomas_e »

Yes, we have some changes on the backend, and want to fetch them on the frontend.
Yes, we are using loadOnDemand feature (lazyLoad - see config in previous post).

No, replaceChildren is not an option. This would mean to build a separate logic for the loadOnDemand feature (manually pull data from the backend and wrap it to a Model).

We want the grid to know which data to load, when updateing a sub-node of the tree. The grid already knows

  • which url to use, to call the Model from the backend

  • which slize (startRow, count) to use when loading the Model from the backend

  • which filter to sent to the backend

What we need is: An option on how to update the data of a node by using the grids tree and lazyLoad features - because: When the grid (a sub-node) is loaded once, it seems to be never be updated again.


Post by thomas_e »

I have created a github repo and a video showing the bug.
Please feel free to clone and reproduce:

https://github.com/ekert-it/bryntumissue

Thank you.


Post by joakim.l »

Hi

There is currently no support for reloading a part of a dataset which has already been reloaded.

It might be that some or all of the exceptions you are getting will not be there in version 6.2.2 since we've done quite a few changes on remote filtering a lazy loaded store.

So either you reload completely, or you need to handle the updated the data manually. Maybe https://bryntum.com/products/grid/docs/#Core/data/mixin/StoreChanges#function-applyChangeset could help?

Regards
Joakim


Post by thomas_e »

Hi,
thank you for your response. We are quite desperate since our backend has quite complex logic that will make it hard to implement that kind of manual change. However we will try 6.2.2.

  • When will it be launched?

Since we experience similar phenomena when using (Ajax-)store.remove(record) combined with (Ajax-)store.filter(..) I am wondering

  • what constraints apply on (Ajax-)store.filter when using a backend that returns filtered data when a filter applies?

  • What does the backend need to comply to?

  • Besides returning the filtered set (when the ajax store calls its readUrl) what do we need to be aware of?

And: It seems to me that after store.remove(record) I ADDITIONALLY do have to call store.applyChangeset(removed : ...).

  • Is this correct?

Thank you so much. Any help is highly appreciated!

Best, Thomas


Post by joakim.l »

6.2.2 will most likely be out by the end of next week.

You should take a look at our AjaxStore guide , it should mention all that is needed to get it to work.

Regards
Joakim


Post by thomas_e »

Hi there, thank you for your reply. Yes, we followed your AjaxStore guide in detail when we set up our application. Backend filtering works fine - unless we dont need to refresh data.

Could you please try to answer my question "Do I have to additionally call store.applyChangeset(removed : ...) after store.remove(record)" - Or do we have to use "store.applyChangeset(removed : ...)" instead of store.remove()?
If we (only) use store.remove(record) we observer similar issues with filtering...


Post by marcio »

Hey thomas_e,

If you check this section https://bryntum.com/products/grid/docs/guide/Grid/data/ajaxstore#removed-records you'll see that you need to run store.commit() after using store.remove(record).

Best regards,
Márcio

How to ask for help? Please read our Support Policy


Post Reply