Skip to content

Commit

Permalink
feat: Allow to display children of found matches (#204)
Browse files Browse the repository at this point in the history
* Use different classname than bootstrap

`hide` classname is being used by bootstrap to hide elements. For us, we need to change the classname here in react-dropdown-tree-select to display everything correctly.

* Option to show children on search results

This allows for children of found matches to be displayed. With this option, one can search for the parent and then see all children and select any.

* Add docs/bundle.js

* Remove unnecessary line

* nicer code

* Code optimization

* Rename addChildrensToTree

* Update docs

* ESLint

* Remove bootstrap hide workaround

* test: Updated syntax after merging latest develop

* chore: Updated bundle after merging latest develop
  • Loading branch information
mobilutz authored and mrchief committed Feb 18, 2019
1 parent 621988a commit 0b78b5d
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 14 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ A lightweight and fast control to render a select component that can display hie
- [placeholderText](#placeholdertext)
- [noMatchesText](#nomatchestext)
- [keepTreeOnSearch](#keeptreeonsearch)
- [keepChildrenOnSearch](#keepchildrenonsearch)
- [simpleSelect](#simpleselect)
- [showPartiallySelected](#showpartiallyselected)
- [showDropdown](#showDropdown)
Expand Down Expand Up @@ -275,6 +276,14 @@ Type: `bool`

Displays search results as a tree instead of flattened results

### keepChildrenOnSearch

Type: `bool`

Displays children of found nodes to allow searching for a parent node on then selecting any child node of the found node. Defaults to `false`

*NOTE* this works only in combination with `keepTreeOnSearch`

### simpleSelect

Type: `bool` (default: `false`)
Expand Down
2 changes: 1 addition & 1 deletion docs/bundle.js

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class DropdownTreeSelect extends Component {
data: PropTypes.oneOfType([PropTypes.object, PropTypes.array]).isRequired,
clearSearchOnChange: PropTypes.bool,
keepTreeOnSearch: PropTypes.bool,
keepChildrenOnSearch: PropTypes.bool,
placeholderText: PropTypes.string,
showDropdown: PropTypes.bool,
className: PropTypes.string,
Expand Down Expand Up @@ -117,7 +118,7 @@ class DropdownTreeSelect extends Component {
}

onInputChange = value => {
const { allNodesHidden, tree } = this.treeManager.filterTree(value, this.props.keepTreeOnSearch)
const { allNodesHidden, tree } = this.treeManager.filterTree(value, this.props.keepTreeOnSearch, this.props.keepChildrenOnSearch)
const searchModeOn = value.length > 0

this.setState({
Expand Down Expand Up @@ -220,6 +221,7 @@ class DropdownTreeSelect extends Component {
<Tree
data={this.state.tree}
keepTreeOnSearch={this.props.keepTreeOnSearch}
keepChildrenOnSearch={this.props.keepChildrenOnSearch}
searchModeOn={this.state.searchModeOn}
onAction={this.onAction}
onCheckboxChange={this.onCheckboxChange}
Expand Down
21 changes: 20 additions & 1 deletion src/tree-manager/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,22 @@ class TreeManager {
}
}

filterTree(searchTerm, keepTreeOnSearch) {
addChildrenToTree(ids, tree, matches) {
if (ids !== undefined) {
ids.forEach(id => {
if (matches && matches.includes(id)) {
// if a child is found by search anyways, don't display it as a child here
return
}
const node = this.getNodeById(id)
node.matchInParent = true
tree.set(id, node)
this.addChildrenToTree(node._children, tree)
})
}
}

filterTree(searchTerm, keepTreeOnSearch, keepChildrenOnSearch) {
const matches = this.getMatches(searchTerm.toLowerCase())

const matchTree = new Map()
Expand All @@ -78,6 +93,10 @@ class TreeManager {
this.addParentsToTree(node._parent, matchTree)
}
matchTree.set(m, node)
if (keepTreeOnSearch && keepChildrenOnSearch) {
// add children nodes after a found match
this.addChildrenToTree(node._children, matchTree, matches)
}
})

const allNodesHidden = matches.length === 0
Expand Down
2 changes: 1 addition & 1 deletion src/tree-manager/tests/flatten-tree.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ test('does not check parent with empty children when showing partial state', t =
name: 'item3',
value: 'value3',
partial: false
},
}
}

const { list } = flattenTree(tree, false, true)
Expand Down
31 changes: 31 additions & 0 deletions src/tree-manager/tests/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -543,3 +543,34 @@ test('should restore default values', t => {
t.true(manager.getNodeById('c1').checked)
t.true(manager.getNodeById('i2').checked)
})

test('should return children when search with `keepChildrenOnSearch`', t => {
const tree = [
{
id: 'i1',
label: 'search me',
value: 'v1',
children: [
{
id: 'c1',
label: 'SeaRch me too',
value: 'l1v1',
children: [
{
id: 'c2',
label: 'You can see me',
value: 'l2v1'
}
]
}
]
}
]
const manager = new TreeManager({ data: tree })
const keepTreeOnSearch = true
const keepChildrenOnSearch = true
const { allNodesHidden, tree: matchTree } = manager.filterTree('search me', keepTreeOnSearch, keepChildrenOnSearch)
t.false(allNodesHidden)
const nodes = ['i1', 'c1', 'c2']
nodes.forEach(n => t.not(matchTree.get(n), undefined))
})
7 changes: 6 additions & 1 deletion src/tree-node/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ const cx = cn.bind(styles)
const isLeaf = children => isEmpty(children)

const getNodeCx = props => {
const { keepTreeOnSearch, _children, matchInChildren, disabled, partial, hide, className, showPartiallySelected, readOnly } = props
const {
keepTreeOnSearch, keepChildrenOnSearch, _children, matchInChildren, matchInParent,
disabled, partial, hide, className, showPartiallySelected, readOnly
} = props

return cx(
'node',
Expand All @@ -24,6 +27,7 @@ const getNodeCx = props => {
disabled,
hide,
'match-in-children': keepTreeOnSearch && matchInChildren,
'match-in-parent': keepTreeOnSearch && keepChildrenOnSearch && matchInParent,
partial: showPartiallySelected && partial,
readOnly
},
Expand All @@ -47,6 +51,7 @@ class TreeNode extends PureComponent {
partial: PropTypes.bool,
dataset: PropTypes.object,
keepTreeOnSearch: PropTypes.bool,
keepChildrenOnSearch: PropTypes.bool,
searchModeOn: PropTypes.bool,
onNodeToggle: PropTypes.func,
onAction: PropTypes.func,
Expand Down
13 changes: 4 additions & 9 deletions src/tree/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Tree extends Component {
static propTypes = {
data: PropTypes.object,
keepTreeOnSearch: PropTypes.bool,
keepChildrenOnSearch: PropTypes.bool,
searchModeOn: PropTypes.bool,
onChange: PropTypes.func,
onNodeToggle: PropTypes.func,
Expand Down Expand Up @@ -59,22 +60,16 @@ class Tree extends Component {

getNodes = props => {
const {
data,
keepTreeOnSearch,
searchModeOn,
simpleSelect,
showPartiallySelected,
readOnly,
onAction,
onChange,
onCheckboxChange,
data, keepTreeOnSearch, keepChildrenOnSearch, searchModeOn, simpleSelect,
showPartiallySelected, readOnly, onAction, onChange, onCheckboxChange,
onNodeToggle
} = props
const items = []
data.forEach(node => {
if (shouldRenderNode(node, searchModeOn, data)) {
items.push(<TreeNode
keepTreeOnSearch={keepTreeOnSearch}
keepChildrenOnSearch={keepChildrenOnSearch}
key={node._id}
{...node}
searchModeOn={searchModeOn}
Expand Down

0 comments on commit 0b78b5d

Please sign in to comment.