Skip to content

Commit 7cd79ad

Browse files
committed
Fixed an issue rendering blank lines when filtering out nodes
1 parent 94ca974 commit 7cd79ad

File tree

4 files changed

+194
-13
lines changed

4 files changed

+194
-13
lines changed

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,16 @@ export default (props) => (
6666
<InfiniteTree
6767
width="100%"
6868
height={400}
69-
rowHeight={30}
69+
rowHeight={({ node, tree }) => {
70+
// Returns zero height to filter out nodes
71+
if (node.state.filtered === false) {
72+
return 0;
73+
}
74+
return 30;
75+
}}
7076
data={props.data}
7177
>
72-
{({ tree, node }) => {
78+
{({ node, tree }) => {
7379
// Determine the toggle state
7480
let toggleState = '';
7581
const hasChildren = node.hasChildren();
@@ -184,8 +190,8 @@ tabIndex | Number | 0 | Specifies the tab order to make tree focusable.
184190
data | Array or Object | [] | Tree data structure, or a collection of tree data structures.
185191
width \* | Number or String | '100%' | Width of the tree.
186192
height \* | Number or String | | Height of the tree.
187-
rowHeight \* | Number, Array, or Function(index: Number): Number | | Either a fixed height, an array containing the heights of all the rows, or a function that returns the height of a row given its index.
188-
rowRenderer | Function({ node: Node, tree: Tree }): React Node | | A row renderer for rendering a tree node.
193+
rowHeight \* | Number, Array, or Function({ node: Node, tree: Tree, index: Number }): Number | | Either a fixed height, an array containing the heights of all the rows, or a function that returns the height of the given node.
194+
rowRenderer | Function({ node: Node, tree: Tree, index: Number }): React Node | | A row renderer for rendering a tree node.
189195
loadNodes | Function(parentNode: Node, done: Function) | | Loads nodes on demand.
190196
shouldSelectNode | Function(node: Node): Boolean | | Provides a function to determine if a node can be selected or deselected. The function must return `true` or `false`. This function will not take effect if `selectable` is not `true`.
191197
scrollOffset | Number | | Controls the scroll offset.

examples/App.jsx

Lines changed: 135 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,155 @@
11
import React, { PureComponent } from 'react';
22
import Tree from './Tree';
33
import Preview from './Preview';
4+
import debounce from 'lodash.debounce';
45

56
class App extends PureComponent {
67
state = {
7-
node: null
8+
node: null,
9+
filterText: '',
10+
caseSensitive: false,
11+
exactMatch: false,
12+
includeAncestors: true,
13+
includeDescendants: true
814
};
915

16+
textFilter = null;
17+
tree = null;
18+
19+
changeCheckedState = (key) => (event) => {
20+
const checked = event.target.checked;
21+
22+
this.setState({
23+
[key]: checked
24+
}, () => {
25+
this.filter();
26+
});
27+
};
1028
onUpdate = (node) => {
1129
this.setState({ node: node });
1230
};
31+
filter = (keyword) => {
32+
if (!this.tree) {
33+
return;
34+
}
35+
36+
keyword = keyword || this.textFilter.value || '';
37+
38+
if (!keyword) {
39+
this.tree.unfilter();
40+
return;
41+
}
42+
43+
const {
44+
caseSensitive,
45+
exactMatch,
46+
includeAncestors,
47+
includeDescendants
48+
} = this.state;
49+
50+
this.tree.filter(keyword, {
51+
filterPath: 'name',
52+
caseSensitive: caseSensitive,
53+
exactMatch: exactMatch,
54+
includeAncestors: includeAncestors,
55+
includeDescendants: includeDescendants
56+
});
57+
};
1358

1459
render() {
1560
return (
1661
<div className="container-fluid">
1762
<div className="row">
1863
<div className="col-xs-6">
19-
<Tree onUpdate={this.onUpdate} />
64+
<h4>Filter</h4>
65+
<input
66+
ref={node => {
67+
this.textFilter = node;
68+
}}
69+
type="text"
70+
className="form-control"
71+
name="text-filter"
72+
placeholder="Type to filter by text"
73+
onKeyUp={(event) => {
74+
event.persist();
75+
76+
const { keyCode } = event;
77+
const BACKSPACE = 8;
78+
const DELETE = 46;
79+
const ENTER = 13;
80+
81+
if ([BACKSPACE, DELETE, ENTER].includes(keyCode)) {
82+
this.filter();
83+
}
84+
}}
85+
onKeyPress={debounce((event) => {
86+
this.filter();
87+
}, 250)}
88+
/>
89+
<div className="row">
90+
<div className="col-xs-6">
91+
<div className="checkbox" style={{ margin: '5px 0' }}>
92+
<label>
93+
<input
94+
type="checkbox"
95+
name="case-sensitive"
96+
checked={this.state.caseSensitive}
97+
onChange={this.changeCheckedState('caseSensitive')}
98+
/>
99+
Case-sensitive
100+
</label>
101+
</div>
102+
</div>
103+
<div className="col-xs-6">
104+
<div className="checkbox" style={{ margin: '5px 0' }}>
105+
<label>
106+
<input
107+
type="checkbox"
108+
name="exact-match"
109+
checked={this.state.exactMatch}
110+
onChange={this.changeCheckedState('exactMatch')}
111+
/>
112+
Exact match
113+
</label>
114+
</div>
115+
</div>
116+
<div className="col-xs-6">
117+
<div className="checkbox" style={{ margin: '5px 0' }}>
118+
<label>
119+
<input
120+
type="checkbox"
121+
name="include-ancestors"
122+
checked={this.state.includeAncestors}
123+
onChange={this.changeCheckedState('includeAncestors')}
124+
/>
125+
Include ancestors
126+
</label>
127+
</div>
128+
</div>
129+
<div className="col-xs-6">
130+
<div className="checkbox" style={{ margin: '5px 0' }}>
131+
<label>
132+
<input
133+
type="checkbox"
134+
name="include-descendants"
135+
checked={this.state.includeDescendants}
136+
onChange={this.changeCheckedState('includeDescendants')}
137+
/>
138+
Include descendants
139+
</label>
140+
</div>
141+
</div>
142+
</div>
143+
</div>
144+
</div>
145+
<div className="row">
146+
<div className="col-xs-6">
147+
<Tree
148+
ref={c => {
149+
this.tree = c ? c.tree : null;
150+
}}
151+
onUpdate={this.onUpdate}
152+
/>
20153
</div>
21154
<div className="col-xs-6">
22155
<Preview node={this.state.node} />

examples/Tree.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ class Tree extends PureComponent {
8686
data={this.data}
8787
width="100%"
8888
height={400}
89-
rowHeight={30}
9089
rowRenderer={({ node, tree }) => {
9190
const hasChildren = node.hasChildren();
9291

@@ -100,6 +99,12 @@ class Tree extends PureComponent {
10099

101100
return renderTreeNode({ node, tree, toggleState });
102101
}}
102+
rowHeight={({ node, tree }) => {
103+
if (node.state.filtered === false) {
104+
return 0;
105+
}
106+
return 30;
107+
}}
103108
loadNodes={(parentNode, done) => {
104109
const suffix = parentNode.id.replace(/(\w)+/, '');
105110
const nodes = [

src/InfiniteTree.jsx

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,26 @@ export default class extends Component {
122122

123123
this.tree = new InfiniteTree(options);
124124

125+
// Filters nodes.
126+
// https://github.com/cheton/infinite-tree/wiki/Functions:-Tree#filterpredicate-options
127+
const treeFilter = this.tree.filter.bind(this.tree);
128+
this.tree.filter = (...args) => {
129+
setTimeout(() => {
130+
this.virtualList.recomputeSizes(0);
131+
}, 0);
132+
return treeFilter(...args);
133+
};
134+
135+
// Unfilter nodes.
136+
// https://github.com/cheton/infinite-tree/wiki/Functions:-Tree#unfilter
137+
const treeUnfilter = this.tree.unfilter.bind(this.tree);
138+
this.tree.unfilter = (...args) => {
139+
setTimeout(() => {
140+
this.virtualList.recomputeSizes(0);
141+
}, 0);
142+
return treeUnfilter(...args);
143+
};
144+
125145
// Sets the current scroll position to this node.
126146
// @param {Node} node The Node object.
127147
// @return {boolean} Returns true on success, false otherwise.
@@ -253,16 +273,33 @@ export default class extends Component {
253273
width={width}
254274
height={height}
255275
itemCount={count}
256-
itemSize={rowHeight}
257-
renderItem={({ index, style }) => {
258-
let row = null;
259-
if (typeof render === 'function' && this.tree && this.tree.nodes.length > 0) {
260-
row = render({
276+
itemSize={(index) => {
277+
let height = rowHeight;
278+
279+
if (typeof rowHeight === 'function') {
280+
height = rowHeight({
281+
node: this.tree.nodes[index],
261282
tree: this.tree,
262-
node: this.tree.nodes[index]
283+
index: index
263284
});
264285
}
265286

287+
return height;
288+
}}
289+
renderItem={({ index, style }) => {
290+
let row = null;
291+
292+
if (typeof render === 'function') {
293+
const node = this.tree.nodes[index];
294+
if (node && node.state.filtered !== false) {
295+
row = render({
296+
node: this.tree.nodes[index],
297+
tree: this.tree,
298+
index: index
299+
});
300+
}
301+
}
302+
266303
return (
267304
<div key={index} style={style}>
268305
{row}

0 commit comments

Comments
 (0)