From 330ac9fbef05ed4f2e58a884459a035d27d3ad34 Mon Sep 17 00:00:00 2001 From: Thomas Shafer Date: Fri, 16 Oct 2015 14:34:44 -0700 Subject: [PATCH] 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 --- README.md | 21 +++++++++++++++++++++ src/tokenizer/index.js | 42 +++++++++++++++++++++++++++--------------- test/tokenizer-test.js | 37 +++++++++++++++++++++++++++++-------- 3 files changed, 77 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 2eed6e12..50bb1557 100644 --- a/README.md +++ b/README.md @@ -328,6 +328,27 @@ Type: `Function` A function to return the currently selected tokens. +#### tokenizer.addSelectedToken + +Type: `Function` + +A function to add a token to the selected list. +> This does not call `props.onTokenAdd(value)` + +#### tokenizer.removeSelectedToken + +Type: `Function` + +A function to remove a token to the selected list. +> This does not call `props.onTokenRemove(value)` + +#### tokenizer.setSelectedTokens + +Type: `Function` + +A function to remove all currently selected tokens and overwrite the selected list. +> This does not call `props.onTokenAdd(value) or props.onTokenRemove(value)` + ## Developing ### Setting Up diff --git a/src/tokenizer/index.js b/src/tokenizer/index.js index c931688a..5237f1e6 100644 --- a/src/tokenizer/index.js +++ b/src/tokenizer/index.js @@ -81,13 +81,6 @@ var TypeaheadTokenizer = React.createClass({ }; }, - componentWillReceiveProps: function(nextProps){ - // if we get new defaultProps, update selected - if (_arraysAreDifferent(this.props.defaultSelected, nextProps.defaultSelected)){ - this.setState({selected: nextProps.defaultSelected.slice(0)}) - } - }, - focus: function(){ this.refs.typeahead.focus(); }, @@ -96,6 +89,30 @@ var TypeaheadTokenizer = React.createClass({ return this.state.selected; }, + setSelectedTokens: function(tokens){ + this.setState({selected: tokens.slice(0)}); + }, + + addSelectedToken: function(value){ + if (this.state.selected.indexOf(value) != -1) { + return; + } + this.state.selected.push(value); + this.setState({selected: this.state.selected}); + return true; + }, + + removeSelectedToken: function(value){ + var index = this.state.selected.indexOf(value); + if (index == -1) { + return; + } + + this.state.selected.splice(index, 1); + this.setState({selected: this.state.selected}); + return true; + }, + // TODO: Support initialized tokens // _renderTokens: function() { @@ -147,25 +164,20 @@ var TypeaheadTokenizer = React.createClass({ }, _removeTokenForValue: function(value) { - var index = this.state.selected.indexOf(value); - if (index == -1) { + if (!this.removeSelectedToken(value)) { return; } - - this.state.selected.splice(index, 1); - this.setState({selected: this.state.selected}); this.props.onTokenRemove(value); return; }, _addTokenForValue: function(value) { - if (this.state.selected.indexOf(value) != -1) { + if (!this.addSelectedToken(value)) { return; } - this.state.selected.push(value); - this.setState({selected: this.state.selected}); this.refs.typeahead.setEntryText(""); this.props.onTokenAdd(value); + return; }, render: function() { diff --git a/test/tokenizer-test.js b/test/tokenizer-test.js index 55aefd7a..ee301c37 100644 --- a/test/tokenizer-test.js +++ b/test/tokenizer-test.js @@ -170,16 +170,37 @@ describe('TypeaheadTokenizer Component', function() { this.component.focus(); assert.equal(this.component.refs.typeahead.focus.calledOnce, true); }); - }); - it('should provide an exposed component function to get the selected tokens', function() { - simulateTokenInput(this.component, 'o'); - var entry = this.component.refs.typeahead.refs.entry; - TestUtils.Simulate.keyDown(entry, { keyCode: Keyevent.DOM_VK_DOWN }); - TestUtils.Simulate.keyDown(entry, { keyCode: Keyevent.DOM_VK_RETURN }); + it('should provide an exposed component function to get the selected tokens', function() { + simulateTokenInput(this.component, 'o'); + var entry = this.component.refs.typeahead.refs.entry; + TestUtils.Simulate.keyDown(entry, { keyCode: Keyevent.DOM_VK_DOWN }); + TestUtils.Simulate.keyDown(entry, { keyCode: Keyevent.DOM_VK_RETURN }); + + assert.equal(this.component.getSelectedTokens().length, 1); + assert.equal(this.component.getSelectedTokens()[0], "John"); + }); + + it('should provide an exposed component function to add tokens', function() { + this.component.addSelectedToken("John") + assert.equal(this.component.getSelectedTokens().length, 1); + assert.equal(this.component.getSelectedTokens()[0], "John"); + }); + + it('should provide an exposed component function to remove tokens', function() { + this.component.addSelectedToken("John") + assert.equal(this.component.getSelectedTokens().length, 1); + this.component.removeSelectedToken("John") + assert.equal(this.component.getSelectedTokens().length, 0); + }); - assert.equal(this.component.getSelectedTokens().length, 1); - assert.equal(this.component.getSelectedTokens()[0], "John"); + it('should provide an exposed component function to remove tokens', function() { + this.component.addSelectedToken("John") + this.component.setSelectedTokens(["Paul", "George"]) + assert.equal(this.component.getSelectedTokens().length, 2); + assert.equal(this.component.getSelectedTokens()[0], "Paul"); + assert.equal(this.component.getSelectedTokens()[1], "George"); + }); }); describe('keyboard controls', function() {