Skip to content

Commit 330ac9f

Browse files
committed
added component functions to manipulate selected list
changed defaultSelected to no longer modify the selected list after the first render I accidentally fell into the trap of https://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html
1 parent 65f07af commit 330ac9f

File tree

3 files changed

+77
-23
lines changed

3 files changed

+77
-23
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,27 @@ Type: `Function`
328328

329329
A function to return the currently selected tokens.
330330

331+
#### tokenizer.addSelectedToken
332+
333+
Type: `Function`
334+
335+
A function to add a token to the selected list.
336+
> This does not call `props.onTokenAdd(value)`
337+
338+
#### tokenizer.removeSelectedToken
339+
340+
Type: `Function`
341+
342+
A function to remove a token to the selected list.
343+
> This does not call `props.onTokenRemove(value)`
344+
345+
#### tokenizer.setSelectedTokens
346+
347+
Type: `Function`
348+
349+
A function to remove all currently selected tokens and overwrite the selected list.
350+
> This does not call `props.onTokenAdd(value) or props.onTokenRemove(value)`
351+
331352
## Developing
332353

333354
### Setting Up

src/tokenizer/index.js

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,6 @@ var TypeaheadTokenizer = React.createClass({
8181
};
8282
},
8383

84-
componentWillReceiveProps: function(nextProps){
85-
// if we get new defaultProps, update selected
86-
if (_arraysAreDifferent(this.props.defaultSelected, nextProps.defaultSelected)){
87-
this.setState({selected: nextProps.defaultSelected.slice(0)})
88-
}
89-
},
90-
9184
focus: function(){
9285
this.refs.typeahead.focus();
9386
},
@@ -96,6 +89,30 @@ var TypeaheadTokenizer = React.createClass({
9689
return this.state.selected;
9790
},
9891

92+
setSelectedTokens: function(tokens){
93+
this.setState({selected: tokens.slice(0)});
94+
},
95+
96+
addSelectedToken: function(value){
97+
if (this.state.selected.indexOf(value) != -1) {
98+
return;
99+
}
100+
this.state.selected.push(value);
101+
this.setState({selected: this.state.selected});
102+
return true;
103+
},
104+
105+
removeSelectedToken: function(value){
106+
var index = this.state.selected.indexOf(value);
107+
if (index == -1) {
108+
return;
109+
}
110+
111+
this.state.selected.splice(index, 1);
112+
this.setState({selected: this.state.selected});
113+
return true;
114+
},
115+
99116
// TODO: Support initialized tokens
100117
//
101118
_renderTokens: function() {
@@ -147,25 +164,20 @@ var TypeaheadTokenizer = React.createClass({
147164
},
148165

149166
_removeTokenForValue: function(value) {
150-
var index = this.state.selected.indexOf(value);
151-
if (index == -1) {
167+
if (!this.removeSelectedToken(value)) {
152168
return;
153169
}
154-
155-
this.state.selected.splice(index, 1);
156-
this.setState({selected: this.state.selected});
157170
this.props.onTokenRemove(value);
158171
return;
159172
},
160173

161174
_addTokenForValue: function(value) {
162-
if (this.state.selected.indexOf(value) != -1) {
175+
if (!this.addSelectedToken(value)) {
163176
return;
164177
}
165-
this.state.selected.push(value);
166-
this.setState({selected: this.state.selected});
167178
this.refs.typeahead.setEntryText("");
168179
this.props.onTokenAdd(value);
180+
return;
169181
},
170182

171183
render: function() {

test/tokenizer-test.js

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,16 +170,37 @@ describe('TypeaheadTokenizer Component', function() {
170170
this.component.focus();
171171
assert.equal(this.component.refs.typeahead.focus.calledOnce, true);
172172
});
173-
});
174173

175-
it('should provide an exposed component function to get the selected tokens', function() {
176-
simulateTokenInput(this.component, 'o');
177-
var entry = this.component.refs.typeahead.refs.entry;
178-
TestUtils.Simulate.keyDown(entry, { keyCode: Keyevent.DOM_VK_DOWN });
179-
TestUtils.Simulate.keyDown(entry, { keyCode: Keyevent.DOM_VK_RETURN });
174+
it('should provide an exposed component function to get the selected tokens', function() {
175+
simulateTokenInput(this.component, 'o');
176+
var entry = this.component.refs.typeahead.refs.entry;
177+
TestUtils.Simulate.keyDown(entry, { keyCode: Keyevent.DOM_VK_DOWN });
178+
TestUtils.Simulate.keyDown(entry, { keyCode: Keyevent.DOM_VK_RETURN });
179+
180+
assert.equal(this.component.getSelectedTokens().length, 1);
181+
assert.equal(this.component.getSelectedTokens()[0], "John");
182+
});
183+
184+
it('should provide an exposed component function to add tokens', function() {
185+
this.component.addSelectedToken("John")
186+
assert.equal(this.component.getSelectedTokens().length, 1);
187+
assert.equal(this.component.getSelectedTokens()[0], "John");
188+
});
189+
190+
it('should provide an exposed component function to remove tokens', function() {
191+
this.component.addSelectedToken("John")
192+
assert.equal(this.component.getSelectedTokens().length, 1);
193+
this.component.removeSelectedToken("John")
194+
assert.equal(this.component.getSelectedTokens().length, 0);
195+
});
180196

181-
assert.equal(this.component.getSelectedTokens().length, 1);
182-
assert.equal(this.component.getSelectedTokens()[0], "John");
197+
it('should provide an exposed component function to remove tokens', function() {
198+
this.component.addSelectedToken("John")
199+
this.component.setSelectedTokens(["Paul", "George"])
200+
assert.equal(this.component.getSelectedTokens().length, 2);
201+
assert.equal(this.component.getSelectedTokens()[0], "Paul");
202+
assert.equal(this.component.getSelectedTokens()[1], "George");
203+
});
183204
});
184205

185206
describe('keyboard controls', function() {

0 commit comments

Comments
 (0)