I programmatically create a <List> and some <ListItem>s has nestedItems, the list is created correctly, though the nested items are not indented at all.
I guess that the problem is related on how I create the List, as I interfere with the components hierarchy that material-ui expects, is there another way to do that? or it's an issue with material-ui?
_update 25/07/2016_: the nestedLevel property on the ListItem components is always 0, so the marginLeft CSS property is consequently 0
I need to create a List from an XML file that is something like this:
<navitem>
<navitem>
<navitem />
</navitem>
</navitem>
So I uses a main component:
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>
);
}
});
and a subcomponent:
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}
/>
);
}
});
The list is created with <ConfigurationNav nav={this.state.nav}/>
Same problem here. Have you found a solution beside giving the subelements a margin-left?
not yet, now I put aside this problem and kept the list without indent. that's pretty awful though.
I took a look at material-ui source code and probably we can hack the property nestedLevel that is used to compute the margin-left, but i didn't try yet
It seems the ListItem component's nestedItems prop only accepts ListItem components for proper indentation, I believe that is the root of this issue...
It should really accept any component, as I'm wrapping my children ListItem's in container components, some of which relay on a base div to work properly.
FYI, a simple workaround for this right now is to add this prop to the parent ListItem component:
nestedListStyle={{ marginLeft: 18 }}
If you are in fact using ListItem children but need to wrap them within div components or something similar, you can also pass this prop to the children:
nestedLevel={1}
There is a bug somewhere in the code. I looked around and couldn't find exactly where this was happening, as by looking at the code it seems to be set correctly https://github.com/callemall/material-ui/blob/master/src/List/ListItem.js#L52 -- perhaps this is happening somewhere else.
I was abble to achieve this via recursive function.
const recursiveList = (node, index) => {
const children = node.children.map(
(node, i) => recursiveList(node, i)
);
const item = (
<ListItem
key={index}
primaryText={node.title}
primaryTogglesNestedList={true}
nestedItems={children}
/>
);
return item;
};
class Page extends Component {
render() {
const tree = [
{
title: "Category1",
children: [
{
title: "foo",
children: []
},
{
title: "bar",
children: [
{
title: "so deep",
children: []
},
{
title: "inception",
children: []
}
]
}
]
}
];
return (
<List>
{tree.map(
(node, i) => recursiveList(node, i)
)}
</List>
);
}
}
Just stumbled over this issue, when encountering the same problem and looking for a solution.
Basically, the indentation in _material-ui_'s List component is achieved via the ListItem component. It has a property nestedLevel with a default value of 0. When ListItem elements are inserted via the nestedItems attribute, they are wrapped into a NestedList element which increments the parents nestedLevel and forwards it to its children. Thus, only ListItem components and other components which have a nestedLevel property and use it to control their own indentation are nicely indented.
If you just want to wrap a ListItem into another component, you could give it a property nestedLevel (with the default value 0) that is forwarded to the wrapped ListItem. As opposed to the workaround proposed by @markoshust, this works also if the element is inserted in deeper or changing nesting levels.
import React from 'react';
var NestedComponent = React.createClass({
propTypes: {
// Define the nestedLevel property
nestedLevel: React.PropTypes.number,
},
getDefaultProps() {
return {
// Set the default value for the nestedLevel property
nestedLevel: 0,
};
},
render() {
return (
// Create the wrapped ListItem element and forward the nestedLevel property
<ListItem key={/*The key of the list item*/}
primaryText='The primary text of the list item'
nestedItems={/*Whatever you want to nest into the list item*/}
nestedLevel={nestedLevel}
/>
);
}
});
If you do not want to wrap a ListItem component you need to implement the indentation yourself, e.g. using margin-left. This is the same thing that ListItem does. In order to allow for deeper nesting levels, also provide your component with a nestedLevel property. In _material-ui_ the nestedLevelDepth is retrieved from this.context.muiTheme.listItem.nestedLevelDepth, but you might define your own indentation depth. The code might look as follows:
import React from 'react';
var NestedComponent = React.createClass({
propTypes: {
// Define the nestedLevel property
nestedLevel: React.PropTypes.number,
},
getDefaultProps() {
return {
// Set the default value for the nestedLevel property
nestedLevel: 0,
};
},
contextTypes: {
// Define the requirement for a muiTheme object in the context
muiTheme: React.PropTypes.object.isRequried,
},
render() {
const {listItem} = this.context.muiTheme;
const {nestedLevel} = this.props;
const styles = {
innerDiv: {
marginLeft: nestedLevel * listItem.nestedLevelDepth,
},
};
return (
// Indent the inner div or any other wrapped element
<div style={styles.innerDiv}></div>
);
}
});
However, as Facebooks favours the use of ES2015 (_"Our eventual goal is for ES6 classes to replace React.createClass completely"_, https://facebook.github.io/react/blog/2015/03/10/react-v0.13.html), here comes the corresponding code.
ES2015:
import React from 'react';
class NestedComponent extends React.Component {
render() {
const {listItem} = this.context.muiTheme;
const {nestedLevel} = this.props;
const styles = {
innerDiv: {
marginLeft: nestedLevel * listItem.nestedLevelDepth,
},
};
return (
// Indent the inner div or any other wrapped element
<div style={styles.innerDiv}></div>
);
}
}
NestedComponent.propTypes = {
// Define the nestedLevel property
nestedLevel: React.PropTypes.number,
};
NestedComponent.defaultProps = {
// Set the default value for the nestedLevel property
nestedLevel: 0,
};
NestedComponent.contextTypes = {
// Define the requirement for a muiTheme object in the context
muiTheme: React.PropTypes.object.isRequried,
};
It's now users responsibility to set the text indent CSS property on the v1-beta branch.
@oliviertassinari Could you provide a complete example of a nested list in v1-beta?
@athrunsun We have been doing the following for the documentation:
https://github.com/callemall/material-ui/blob/1a9b612c02cd606a3ae31c8a241505a2e8e67264/docs/src/modules/components/AppDrawerNavItem.js#L88-L101
Most helpful comment
Just stumbled over this issue, when encountering the same problem and looking for a solution.
Basically, the indentation in _material-ui_'s
Listcomponent is achieved via theListItemcomponent. It has a propertynestedLevelwith a default value of 0. WhenListItemelements are inserted via thenestedItemsattribute, they are wrapped into aNestedListelement which increments the parentsnestedLeveland forwards it to its children. Thus, onlyListItemcomponents and other components which have anestedLevelproperty and use it to control their own indentation are nicely indented.If you just want to wrap a
ListIteminto another component, you could give it a propertynestedLevel(with the default value 0) that is forwarded to the wrappedListItem. As opposed to the workaround proposed by @markoshust, this works also if the element is inserted in deeper or changing nesting levels.If you do not want to wrap a
ListItemcomponent you need to implement the indentation yourself, e.g. using margin-left. This is the same thing thatListItemdoes. In order to allow for deeper nesting levels, also provide your component with anestedLevelproperty. In _material-ui_ thenestedLevelDepthis retrieved fromthis.context.muiTheme.listItem.nestedLevelDepth, but you might define your own indentation depth. The code might look as follows: