Skip to content

Commit a7646b7

Browse files
committed
Make component throw an error when nodes have duplicate values
Addresses #211.
1 parent 22c8a6c commit a7646b7

File tree

5 files changed

+52
-0
lines changed

5 files changed

+52
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### New Features
66

77
* [#182]: Add `direction` property to support RTL languages
8+
* [#211]: Throw an error when nodes have duplicate values
89

910
## [v1.6.0](https://github.com/jakezatecky/react-checkbox-tree/compare/v1.5.0...v1.6.0) (2019-12-11)
1011

src/js/CheckboxTree.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class CheckboxTree extends React.Component {
117117

118118
// Since flattening nodes is an expensive task, only update when there is a node change
119119
if (!isEqual(prevProps.nodes, nodes) || prevProps.disabled !== disabled) {
120+
model.reset();
120121
model.flattenNodes(nodes);
121122
}
122123

src/js/CheckboxTreeError.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function CheckboxTreeError(message) {
2+
this.message = message;
3+
this.stack = Error().stack;
4+
}
5+
6+
CheckboxTreeError.prototype = Object.create(Error.prototype);
7+
CheckboxTreeError.prototype.name = 'CheckboxTreeError';
8+
9+
export default CheckboxTreeError;

src/js/NodeModel.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import CheckboxTreeError from './CheckboxTreeError';
12
import constants from './constants';
23

34
const { CheckModel } = constants;
@@ -28,6 +29,10 @@ class NodeModel {
2829
return this.flatNodes[value];
2930
}
3031

32+
reset() {
33+
this.flatNodes = {};
34+
}
35+
3136
flattenNodes(nodes, parent = {}, depth = 0) {
3237
if (!Array.isArray(nodes) || nodes.length === 0) {
3338
return;
@@ -39,6 +44,13 @@ class NodeModel {
3944
nodes.forEach((node, index) => {
4045
const isParent = this.nodeHasChildren(node);
4146

47+
// Protect against duplicate node values
48+
if (this.flatNodes[node.value] !== undefined) {
49+
throw new CheckboxTreeError(
50+
`Duplicate value '${node.value}' detected. All node values must be unique.`,
51+
);
52+
}
53+
4254
this.flatNodes[node.value] = {
4355
label: node.label,
4456
value: node.value,

test/CheckboxTree.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { shallow, mount } from 'enzyme';
33
import { assert } from 'chai';
44

55
import CheckboxTree from '../src/js/CheckboxTree';
6+
import CheckboxTreeError from '../src/js/CheckboxTreeError';
67
import TreeNode from '../src/js/TreeNode';
78

89
describe('<CheckboxTree />', () => {
@@ -384,6 +385,34 @@ describe('<CheckboxTree />', () => {
384385
assert.equal(true, wrapper.find(TreeNode).prop('isParent'));
385386
assert.equal(false, wrapper.find(TreeNode).prop('isLeaf'));
386387
});
388+
389+
it('should throw an error when duplicate values are used', () => {
390+
let errorMessage = null;
391+
392+
try {
393+
shallow(
394+
<CheckboxTree
395+
nodes={[
396+
{
397+
value: 'jupiter',
398+
label: 'Jupiter',
399+
children: [
400+
{ value: 'jupiter', label: 'Jupiter' },
401+
],
402+
},
403+
]}
404+
/>,
405+
);
406+
} catch (e) {
407+
if (e instanceof CheckboxTreeError) {
408+
errorMessage = e.message;
409+
} else {
410+
throw e;
411+
}
412+
}
413+
414+
assert.equal("Duplicate value 'jupiter' detected. All node values must be unique.", errorMessage);
415+
});
387416
});
388417

389418
describe('noCascade', () => {

0 commit comments

Comments
 (0)