Our blazing fast Grid component built with pure JavaScript


Post by Yamo1993 »

Hi,

Given a record id of a node in the tree, I want to visually turn that record into the root of the tree (basically hide all of its parents). Is this possible?

If you have a big tree structure, you might want to hide parts of it so that you only focus on a subtree and not the entire tree.


Post by Maxim Gorkovsky »

Hello.
We do not support this out of the box, I'm afraid.

So far I can think of two ways to achieve this. Simple way would be to filter the tree store with a function which would return records which belong to the subtree you want to see: https://bryntum.com/docs/grid/#Core/data/Store#function-filterBy

More complex option would be to have a master store, holding entire dataset and stores derived from that master store which are consumed by the grid panel. You can try to chain the master store, in which case records would be synchronized: https://bryntum.com/docs/grid/#Core/data/Store#function-chain

But that only applies to grid. If you want to use that strategy for the gantt panel and task store then filtering is your only option for the time being.

I'm afraid there is not a lot of demand for such feature, so we are not going to include it to our roadmap for next few quarters.

Also there's an option to hire us to help you developing custom feature. If you're interested, please contact sales at bryntum.com for a quote.


Post by Yamo1993 »

Thanks for the reply.

I wrote a function which uses filterBy and looks like this:

            function filterParents (node: any): void {
                const { store } = gridRef.current.gridInstance;
                const recordToFilterBy = store.getById(node.id);
                const childIdsToFilterBy = recordToFilterBy.allChildren.map((child: any) => child.id);
                store.filterBy((record: any) => {
                    if (record.id === recordToFilterBy.id) {
                        return true;
                    }
                    if (childIdsToFilterBy.includes(record.id)) {
                        return true;
                    }
                    return false;
                });
            }

I passed in the given node that I want to turn into a root. I didn't get the desired result though.
The actual result was - the grid showing the node itself, its parents and its children:
[root]
x[parent]
xx[node]
xxx[child]
xxxx[child]

My desired result is - the grid showing the node itself and its children without its parents:
[hidden_root]
x[hidden_parent]
xx[new_root_node]
xxx[child]
xxxx[child]

It basically gives me everything above and under the node in the tree, while I'm only interested in what's under the node. It seems that when you filter a tree column, if it finds a match then it will show the match and all of its parents. I guess that it's reasonable since you normally don't want to "cut off a tree", but it's not my desired result.

Thanks, I will try to experiment with the stores.

Last edited by Yamo1993 on Thu Jul 15, 2021 3:04 pm, edited 4 times in total.

Post by Animal »

You can't get rid of the parents. But the filterBy function you need needs to filter in the descendants, so would look like this:

const myTopNode = <whatever one you want>;

// Filter in the top node, and also any descendants
grid.store.filter(r => r === myTopNode || myTopNode.contains(r))

Outside of the chained store idea, this is the closest you can get.


Post by Yamo1993 »

Animal,

Thanks for the answer. I just edited my post above and added the function that I wrote. My function also looks at the descendants, but as you said: it can't get rid of the parents.

The final output basically becomes a tree which hasn't changed visually, since it can't get rid of the parents, and shouldn't get rid of the children.


Post by Animal »

Probably the best would be to have a Container which is layout : 'card'. Instead of just your tree.

It would contain, in its items configuration, your tree, and also a second "Rooted tree". That would be your second "view" which would begin empty.

When you select the node in the main tree which you want to examine, you could do

// Load up second tree with a new root node which contains our selection
secondTree.store.rootNode = { children : [myTopNode] };

// Switch to make the second tree the visible child of the Container
myContainer.layout.activeItem = 1;

Switching the container's activeItem between 0 and 1 and back would be up to you when switching between this zoomed in concept and back to the main tree


Post by Yamo1993 »

Wow, that sounds like an awesome idea. Thanks! I will try to implement that.


Post by Yamo1993 »

The suggestion mentioned above did not work that well with React.

So far I have tried the following approaches:

  1. Update the store data with a new root node. The problems I encountered from this approach were:
    a) The grid threw a bunch of errors when switching between the main tree and sub tree, like "The parent is not found" and similar errors.

  2. Build a new "card" container which switches between a main tree grid and a sub tree grid, just like @Animal suggested. The problems I encountered from this approach were:
    a) The sync between React and Bryntum was lost. Since I am using column renderers with JSX, the JSX was never re-rendered. I tried to reuse a method from the "WrapperHelper" in the source code for Bryntum to force a re-render of the column renderers, but it didn't work well with my functional component.

  3. Instantiate a new store on the grid instance and set the initial data to the new root node. The problems I encountered from this approach were:
    a) The sync between React and the grid instance was lost again.

I need a solution where the React grid and its column renderers are updated correctly, and the store is also reinstantiated.

It's worth noting that approach no 1 actually worked in an earlier version, where I could set new root nodes each time and it would update correctly.


Post by mats »

Can you please attach error messages and a test case that we can debug?


Post by Yamo1993 »

This is the error message I'm getting when I try to switch to a root node and then go back to its parent:

Uncaught Error: Parent node with id 18769 not found, cannot add children.
    at eval (grid.umd.js?0469:12359)
    at Map.forEach (<anonymous>)
    at Store.add (grid.umd.js?0469:12355)
    at Store.add (grid.umd.js?0469:22515)
    at Store.syncDataset (grid.umd.js?0469:16860)
    at Store.setStoreData (grid.umd.js?0469:9419)
    at Store.set (grid.umd.js?0469:9323)
    at Grid.set (grid.umd.js?0469:124420)
    at eval (WrapperHelper.js?b7f3:599)
    at Array.forEach (<anonymous>)

I will try to create a test case.


Post Reply