Skip to content

Commit

Permalink
Add id property
Browse files Browse the repository at this point in the history
Resolves #123.
  • Loading branch information
jakezatecky committed Jan 22, 2019
1 parent d9a1b88 commit 7bdd598
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 12 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

## v1.4.2 (TBA)

### New Features

* [#123]: Add `id` property

## [v1.4.1](https://github.com/jakezatecky/react-checkbox-tree/compare/v1.4.0...v1.4.1) (2018-09-21)

### Bug Fixes
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ Note that you can override as many or as little icons as you like.
| `expandDisabled` | bool | If true, the ability to expand nodes will be disabled. | `false` |
| `expandOnClick` | bool | If true, nodes will be expanded by clicking on labels. Requires a non-empty `onClick` function. | `false` |
| `icons` | object | An object containing the mappings for the various icons and their components. See **Changing the Default Icons**. | `{ ... }` |
| `id` | string | A string to be used for the HTML IDs of the rendered tree nodes. | `null` |
| `expanded` | array | An array of expanded node values. | `[]` |
| `lang` | object | An object containing the language mappings for the various text elements. | `{ ... }` |
| `name` | string | Optional name for the hidden `<input>` element. | `undefined` |
Expand Down
32 changes: 22 additions & 10 deletions src/js/CheckboxTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class CheckboxTree extends React.Component {
expandOnClick: PropTypes.bool,
expanded: listShape,
icons: iconsShape,
id: PropTypes.string,
lang: languageShape,
name: PropTypes.string,
nameAsArray: PropTypes.bool,
Expand Down Expand Up @@ -55,6 +56,7 @@ class CheckboxTree extends React.Component {
parentOpen: <span className="rct-icon rct-icon-parent-open" />,
leaf: <span className="rct-icon rct-icon-leaf" />,
},
id: null,
lang: {
collapseAll: 'Collapse all',
expandAll: 'Expand all',
Expand Down Expand Up @@ -85,8 +87,9 @@ class CheckboxTree extends React.Component {
});

this.state = {
id: `rct-${nanoid(7)}`,
id: props.id || `rct-${nanoid(7)}`,
model,
prevProps: props,
};

this.onCheck = this.onCheck.bind(this);
Expand All @@ -95,18 +98,27 @@ class CheckboxTree extends React.Component {
this.onCollapseAll = this.onCollapseAll.bind(this);
}

shouldComponentUpdate({ nodes, checked, expanded }) {
// Since flattening nodes is an expensive task, only update the state when there is a change
if (!isEqual(this.props.nodes, nodes)) {
this.state.model.flattenNodes(nodes);
// eslint-disable-next-line react/sort-comp
static getDerivedStateFromProps(newProps, prevState) {
const { model, prevProps } = prevState;
const { id, nodes } = newProps;
let newState = { ...prevState, prevProps: newProps };

// Since flattening nodes is an expensive task, only update when there is a change
if (!isEqual(prevProps.nodes, nodes)) {
model.flattenNodes(nodes);
}

if (id !== null) {
newState = { ...newState, id };
}

this.state.model.deserializeLists({ checked, expanded });
model.deserializeLists({
checked: newProps.checked,
expanded: newProps.expanded,
});

// Always update. We are hijacking this method to act as a hybrid between
// getDerivedStateFromProps and legacy componentWillReceiveProps, updating the internals
// of a state variable.
return true;
return newState;
}

onCheck(nodeInfo) {
Expand Down
6 changes: 4 additions & 2 deletions src/js/NodeModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,17 @@ class NodeModel {
}

deserializeLists(lists) {
const listKeys = ['checked', 'expanded'];

// Reset values to false
Object.keys(this.flatNodes).forEach((value) => {
Object.keys(lists).forEach((listKey) => {
listKeys.forEach((listKey) => {
this.flatNodes[value][listKey] = false;
});
});

// Deserialize values and set their nodes to true
Object.keys(lists).forEach((listKey) => {
listKeys.forEach((listKey) => {
lists[listKey].forEach((value) => {
if (this.flatNodes[value] !== undefined) {
this.flatNodes[value][listKey] = true;
Expand Down
13 changes: 13 additions & 0 deletions test/CheckboxTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,19 @@ describe('<CheckboxTree />', () => {
});
});

describe('id', () => {
it('should pass the property directly to tree nodes', () => {
const wrapper = shallow(
<CheckboxTree
id="my-awesome-id"
nodes={[{ value: 'jupiter', label: 'Jupiter' }]}
/>,
);

assert.equal('my-awesome-id', wrapper.find(TreeNode).prop('treeId'));
});
});

describe('lang', () => {
it('should override default language values', () => {
const wrapper = shallow(
Expand Down

0 comments on commit 7bdd598

Please sign in to comment.