diff --git a/docs/src/app/components/pages/components/List/ExampleNested.js b/docs/src/app/components/pages/components/List/ExampleNested.js
index 0ee790c33c01d9..539aef945c8f9d 100644
--- a/docs/src/app/components/pages/components/List/ExampleNested.js
+++ b/docs/src/app/components/pages/components/List/ExampleNested.js
@@ -6,37 +6,76 @@ import ContentInbox from 'material-ui/svg-icons/content/inbox';
import ContentDrafts from 'material-ui/svg-icons/content/drafts';
import ContentSend from 'material-ui/svg-icons/content/send';
import Subheader from 'material-ui/Subheader';
+import Toggle from 'material-ui/Toggle';
-const ListExampleNested = () => (
-
-
- Nested List Items
- } />
- } />
- }
- initiallyOpen={true}
- primaryTogglesNestedList={true}
- nestedItems={[
- }
- />,
- }
- disabled={true}
- nestedItems={[
- } />,
- ]}
- />,
- ]}
- />
-
-
-);
+export default class ListExampleNested extends React.Component {
-export default ListExampleNested;
+ state = {
+ open: false,
+ };
+
+ handleToggle = () => {
+ this.setState({
+ open: !this.state.open,
+ });
+ };
+
+ handleNestedListToggle = (item) => {
+ this.setState({
+ open: item.state.open,
+ });
+ };
+
+ render() {
+ return (
+
+
+
+
+
+ Nested List Items
+ } />
+ } />
+ }
+ initiallyOpen={true}
+ primaryTogglesNestedList={true}
+ nestedItems={[
+ }
+ />,
+ }
+ disabled={true}
+ nestedItems={[
+ } />,
+ ]}
+ />,
+ }
+ open={this.state.open}
+ onNestedListToggle={this.handleNestedListToggle}
+ nestedItems={[
+ } />,
+ ]}
+ />,
+ ]}
+ />
+
+
+
+ );
+ }
+}
diff --git a/src/List/ListItem.js b/src/List/ListItem.js
index 7840aefd4f931a..8d849f8441605e 100644
--- a/src/List/ListItem.js
+++ b/src/List/ListItem.js
@@ -223,6 +223,10 @@ class ListItem extends Component {
onTouchStart: PropTypes.func,
/** @ignore */
onTouchTap: PropTypes.func,
+ /**
+ * Control toggle state of nested list.
+ */
+ open: PropTypes.bool,
/**
* This is the block element that contains the primary text.
* If a string is passed in, a div tag will be rendered.
@@ -282,6 +286,7 @@ class ListItem extends Component {
onMouseLeave: () => {},
onNestedListToggle: () => {},
onTouchStart: () => {},
+ open: null,
primaryTogglesNestedList: false,
secondaryTextLines: 1,
};
@@ -300,9 +305,15 @@ class ListItem extends Component {
};
componentWillMount() {
- if (this.props.initiallyOpen) {
- this.setState({open: true});
- }
+ this.setState({
+ open: this.props.open === null ? this.props.initiallyOpen === true : this.props.open,
+ });
+ }
+
+ componentWillReceiveProps(nextProps) {
+ // update the state when the component is controlled.
+ if (nextProps.open !== null)
+ this.setState({open: nextProps.open});
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
diff --git a/src/List/ListItem.spec.js b/src/List/ListItem.spec.js
index 0d79ccfcbe6e04..938011e1d55f4e 100644
--- a/src/List/ListItem.spec.js
+++ b/src/List/ListItem.spec.js
@@ -73,4 +73,43 @@ describe('', () => {
assert.ok(wrapper.find('.test-checkbox').length);
assert.strictEqual(wrapper.find(`.${testClass}`).length, 1, 'should have a div with the test class');
});
+
+ it('should initially open nested list', () => {
+ const testClass = 'test-class';
+ const wrapper = shallowWithContext(
+ ,
+ ]}
+ />
+ );
+
+ assert.ok(wrapper.find('NestedList').length);
+ assert.ok(wrapper.find('.test-class').parent().children().nodes[1].props.open === true);
+ });
+
+ it('should toggle nested list', () => {
+ const testClass = 'test-class';
+ const wrapper = shallowWithContext(
+ ,
+ ]}
+ />
+ );
+
+ assert.ok(wrapper.find('.test-class').parent().children().nodes[1].props.open === false);
+ wrapper.setProps({
+ open: true,
+ });
+ assert.ok(wrapper.find('.test-class').parent().children().nodes[1].props.open === true);
+ });
});