Updating Selected ItemsPremium
The TreeView provides specific approaches for working with its data and updating the selected
field.
The available options are:
- Mutating the items directly
- Wrapping the items and mutating the wrapper objects
- Creating copies of data before each update
- Using a helper function
Mutating the Items Directly
The following example demonstrates how to directly update the selected items in a TreeView with single selection.
Mutating the Wrapper Objects
The following example demonstrates how to update the selected items by wrapping them before they are passed to a TreeView with multiple selection. In this way, the TreeView regards the selected
field as part of the wrappers which makes the incoming data immutable.
const tree = [
{
text: 'Furniture',
items: [{ text: 'Tables & Chairs' }, { text: 'Sofas' }, { text: 'Occasional Furniture' }]
},
{
text: 'Decor',
items: [{ text: 'Bed Linen' }, { text: 'Curtains & Blinds' }, { text: 'Carpets' }]
}
];
function wrapTreeViewItems(items) {
return items.map((item) => {
return { item, items: item.items && wrapTreeViewItems(item.items) };
});
}
class App extends React.Component {
state = { data: wrapTreeViewItems(tree) };
render() {
return (
<TreeView
data={this.state.data}
textField="item.text"
aria-multiselectable={true}
onItemClick={this.onItemClick}
expandIcons={true}
onExpandChange={this.onExpandChange}
/>
);
}
onItemClick = (event) => {
event.item.selected = !event.item.selected;
this.forceUpdate();
};
onExpandChange = (event) => {
event.item.expanded = !event.item.expanded;
this.forceUpdate();
};
}
ReactDOM.render(<App />, document.querySelector('my-app'));
Copying Data before Each Update
The TreeView allows you create a copy of the data before each item update and avoid the mutation of the data.
The following example demonstrates how to implement the suggested approach in a TreeView with multiple selection.
class App extends React.Component {
state = { data: tree };
render() {
return <TreeView data={this.state.data} aria-multiselectable={true} onItemClick={this.onItemClick} />;
}
onItemClick = (event) => {
const data = this.state.data.slice();
if (event.itemHierarchicalIndex.indexOf(SEPARATOR) < 0) {
// A root item is selected.
copyAndUpdateItem(Number(event.itemHierarchicalIndex), data);
} else {
// A child item is selected.
const parentIndex = Number(event.itemHierarchicalIndex.split(SEPARATOR)[0]);
const childIndex = Number(event.itemHierarchicalIndex.split(SEPARATOR)[1]);
data[parentIndex] = { ...data[parentIndex] };
data[parentIndex].items = data[parentIndex].items.slice();
copyAndUpdateItem(childIndex, data[parentIndex].items);
}
this.setState({ data });
};
}
const SEPARATOR = '_';
function copyAndUpdateItem(itemIndex, siblings) {
siblings[itemIndex] = { ...siblings[itemIndex] };
siblings[itemIndex].selected = !siblings[itemIndex].selected;
}
const tree = [
{
text: 'Furniture',
expanded: true,
items: [{ text: 'Tables & Chairs' }, { text: 'Sofas' }, { text: 'Occasional Furniture' }]
},
{
text: 'Decor',
expanded: true,
items: [{ text: 'Bed Linen', disabled: true }, { text: 'Curtains & Blinds' }, { text: 'Carpets' }]
}
];
ReactDOM.render(<App />, document.querySelector('my-app'));
Using a Helper Function
The processTreeViewItems
helper function updates the items in an immutable way, that is, works with a copy of the data. While using processTreeViewItems
is similar to creating a copy of the data before each item update, the data
field of the application state does not change. That is why, the helper function approach is useful when other components depend on the data
field.
The following example demonstrates how to introduce an additional state field (select
) which holds the IDs of the selected items and is passed to processTreeViewItems
on each re-render.
const tree = [
{
text: 'Item1',
items: [{ text: 'Item1.1' }, { text: 'Item1.2', items: [{ text: 'Item1.2.1' }] }]
},
{
text: 'Item2',
disabled: true,
items: [{ text: 'Item2.1' }, { text: 'Item2.2' }, { text: 'Item2.3' }]
},
{
text: 'Item3'
}
];
class App extends React.Component {
state = { items: tree, expand: [], select: [] };
render() {
return (
<TreeView
data={processTreeViewItems(this.state.items, { expand: this.state.expand, select: this.state.select })}
expandIcons={true}
onExpandChange={this.onExpandChange}
onItemClick={(event) => this.setState({ select: [event.itemHierarchicalIndex] })}
/>
);
}
onExpandChange = (event) => {
let expand = this.state.expand.slice();
const index = expand.indexOf(event.itemHierarchicalIndex);
index === -1 ? expand.push(event.itemHierarchicalIndex) : expand.splice(index, 1);
this.setState({ expand });
};
}
ReactDOM.render(<App />, document.querySelector('my-app'));