Reputation: 63
I'm building a node tree in React.js using { List, ListItem, MakeSelectable} from 'material-ui/List'. I will eventually wire up JSON data coming from an internal web service call. I have no problem declaratively creating a nested list:
<List>
...
<ListItem
...
nestedItems={[
<ListItem
...
What I want to do is programmatically create this nested structure from the JSON data. It's easy enough to instantiate individual <ListItem>
components and .push them into an array to render, but I'm having trouble getting the nested items into the node structure on the fly.
The best I've been able to do so far is to work from the bottom up, finding a bottom level of JSON nodes, pushing them into an array, creating the parent component, assigning my previously-created array as children of the parent, etc. e.g.
var Children = [
<ListItem key={1} primaryText='Child 1' />
<ListItem key={2} primaryText='Child 2' />
]
then...
var Parents = [
<ListItem key={0} primaryText='Parent 1' nestedItems={Children} />
]
This is a bit cumbersome; is there a more graceful way to map up parents with nested children into a material-ui <List>
?
Upvotes: 5
Views: 10998
Reputation: 2811
Imagine that we have an object similar to the following...
RootObject = {
children: [
{
children: [
{
children: [ {...props}, {...props}]
},
...props,
]
},
{
children: [...],
},
...
{
children: [],
},
],
...props,
}
Now we need to create a tree node that will call itself recursively:
const mapStructure = (nodes) => {
if (nodes) {
return nodes.map(node => (
<ListItem
key={node.id}
primaryText={node.primaryText}
initiallyOpen //optional
nestedItems={mapStructure(node.children)}
/>
));
}
};
And finally:
const DynamicNestedItems = ({ RootObject }) => {
return (
<List>
{mapStructure(RootObject)}
</List>
);
};
export default DynamicNestedItems;
Upvotes: 7
Reputation: 2522
I had the very same problem, the only difference is that I have a menu hierarchy described in XML instead of JSON.
I created a main component ConfigurationNav that you can instantiate with <ConfigurationNav nav={this.state.nav}/>
:
var ConfigurationNav = React.createClass({
render: function() {
var items = [];
var _this = this;
this.props.nav.find('> navitem').each(function(i) {
items.push(<ConfigurationNavItem item={this} />);
});
return (
<List>
{items}
</List>
);
}
});
Then there is a subcomponent that creates the ListItem
s:
var ConfigurationNavItem = React.createClass({
render: function() {
var nested = [];
for (var i=0; i<this.props.item.children.length; i++) {
nested.push(<ConfigurationNavItem item={this.props.item.children[i]} />);
}
return (
<ListItem key={this.props.item.id}
primaryText={this.props.item.getAttribute('label')}
nestedItems={nested}
/>
);
}
});
This approach works for me, but somehow I lost the indent of the nested items, still working on it.
Luca
Upvotes: 1