From 70adc2cc2e98f0277c91d99c3a3787690c53601a Mon Sep 17 00:00:00 2001 From: Alex Good Date: Mon, 7 Dec 2015 18:08:35 +0000 Subject: [PATCH 1/5] Fix issues where typeahead was one step behind input --- src/typeahead/index.js | 31 +++++++++++----------------- test/typeahead-test.js | 46 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/typeahead/index.js b/src/typeahead/index.js index c13d2dd0..5d76f81c 100644 --- a/src/typeahead/index.js +++ b/src/typeahead/index.js @@ -81,9 +81,6 @@ var Typeahead = React.createClass({ getInitialState: function() { return { - // The currently visible set of options - visible: this.getOptionsForValue(this.props.defaultValue, this.props.options), - // This should be called something else, "entryValue" entryValue: this.props.value || this.props.defaultValue, @@ -105,6 +102,10 @@ var Typeahead = React.createClass({ return result; }, + visibleOptions: function(){ + return this.getOptionsForValue(this.state.entryValue, this.props.options); + }, + setEntryText: function(value) { this.refs.entry.value = value; this._onTextEntryUpdated(); @@ -117,7 +118,7 @@ var Typeahead = React.createClass({ _hasCustomValue: function() { if (this.props.allowCustomValues > 0 && this.state.entryValue.length >= this.props.allowCustomValues && - this.state.visible.indexOf(this.state.entryValue) < 0) { + this.visibleOptions().indexOf(this.state.entryValue) < 0) { return true; } return false; @@ -143,7 +144,7 @@ var Typeahead = React.createClass({ return ( 0 ? this.state.visible[0] : null); + selection : (this.visibleOptions().length > 0 ? this.visibleOptions()[0] : null); if (option === null && this._hasCustomValue()) { option = this._getCustomValue(); @@ -234,7 +233,7 @@ var Typeahead = React.createClass({ return; } var newIndex = this.state.selectionIndex === null ? (delta == 1 ? 0 : delta) : this.state.selectionIndex + delta; - var length = this.state.visible.length; + var length = this.visibleOptions().length; if (this._hasCustomValue()) { length += 1; } @@ -283,12 +282,6 @@ var Typeahead = React.createClass({ event.preventDefault(); }, - componentWillReceiveProps: function(nextProps) { - this.setState({ - visible: this.getOptionsForValue(this.state.entryValue, nextProps.options) - }); - }, - render: function() { var inputClasses = {}; inputClasses[this.props.customClasses.input] = !!this.props.customClasses.input; @@ -368,7 +361,7 @@ var Typeahead = React.createClass({ }, _hasHint: function() { - return this.state.visible.length > 0 || this._hasCustomValue(); + return this.visibleOptions().length > 0 || this._hasCustomValue(); } }); diff --git a/test/typeahead-test.js b/test/typeahead-test.js index 83fb658f..49188f53 100644 --- a/test/typeahead-test.js +++ b/test/typeahead-test.js @@ -564,4 +564,50 @@ describe('Typeahead Component', function() { }); }) }); + + context("issue-37", function(){ + var WrappingComponent = React.createClass({ + getInitialState: function(){ + return { + value: "", + options: [ + {value: "a"}, + {value: "ab"}, + {value: "abc"}, + {value: "other"} + ] + }; + }, + onChange: function(event) { + var newState = { + value: event.target.value, + options: this.state.options + }; + this.setState(newState); + }, + render: function() { + return (); + } + }); + + beforeEach(function() { + this.wrappingComponent = TestUtils.renderIntoDocument( + + ); + this.component = TestUtils.findRenderedComponentWithType( + this.wrappingComponent, + Typeahead + ); + }); + + it("should not autocomplete one step behind the input", function() { + var results = simulateTextInput(this.component, "a"); + assert.equal(results.length, 3); + }); + }); }); From cfb9e654b2fe812219ad12834f6aa3bef9181e79 Mon Sep 17 00:00:00 2001 From: Alex Good Date: Mon, 7 Dec 2015 18:10:52 +0000 Subject: [PATCH 2/5] Version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 499cd2c3..8dd7a7e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-typeahead", - "version": "1.1.5", + "version": "1.1.6", "description": "React-based typeahead and typeahead-tokenizer", "keywords": [ "react", From 32ba1b3a13d52236c6434d9f5a22ac07b1cf496d Mon Sep 17 00:00:00 2001 From: Alex Good Date: Mon, 7 Dec 2015 18:25:50 +0000 Subject: [PATCH 3/5] Correctly reference issue in test name --- test/typeahead-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/typeahead-test.js b/test/typeahead-test.js index 49188f53..6a050d9e 100644 --- a/test/typeahead-test.js +++ b/test/typeahead-test.js @@ -565,7 +565,7 @@ describe('Typeahead Component', function() { }) }); - context("issue-37", function(){ + context("issue-128", function(){ var WrappingComponent = React.createClass({ getInitialState: function(){ return { From 58e5899af542d3addbf0d78ff5dfaa6e08c953c2 Mon Sep 17 00:00:00 2001 From: Alex Good Date: Thu, 10 Dec 2015 17:29:06 +0000 Subject: [PATCH 4/5] Update visibleOptions to getVisibleOptions --- src/typeahead/index.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/typeahead/index.js b/src/typeahead/index.js index 5d76f81c..beed3d1d 100644 --- a/src/typeahead/index.js +++ b/src/typeahead/index.js @@ -102,7 +102,7 @@ var Typeahead = React.createClass({ return result; }, - visibleOptions: function(){ + getVisibleOptions: function() { return this.getOptionsForValue(this.state.entryValue, this.props.options); }, @@ -118,7 +118,7 @@ var Typeahead = React.createClass({ _hasCustomValue: function() { if (this.props.allowCustomValues > 0 && this.state.entryValue.length >= this.props.allowCustomValues && - this.visibleOptions().indexOf(this.state.entryValue) < 0) { + this.getVisibleOptions().indexOf(this.state.entryValue) < 0) { return true; } return false; @@ -144,7 +144,7 @@ var Typeahead = React.createClass({ return ( 0 ? this.visibleOptions()[0] : null); + selection : (this.getVisibleOptions().length > 0 ? this.getVisibleOptions()[0] : null); if (option === null && this._hasCustomValue()) { option = this._getCustomValue(); @@ -233,7 +233,7 @@ var Typeahead = React.createClass({ return; } var newIndex = this.state.selectionIndex === null ? (delta == 1 ? 0 : delta) : this.state.selectionIndex + delta; - var length = this.visibleOptions().length; + var length = this.getVisibleOptions().length; if (this._hasCustomValue()) { length += 1; } @@ -361,7 +361,7 @@ var Typeahead = React.createClass({ }, _hasHint: function() { - return this.visibleOptions().length > 0 || this._hasCustomValue(); + return this.getVisibleOptions().length > 0 || this._hasCustomValue(); } }); From 5c3f9bd37d2661ae17b3fc8c8b8bcba9a274a2e9 Mon Sep 17 00:00:00 2001 From: Alex Good Date: Mon, 14 Dec 2015 19:29:31 +0000 Subject: [PATCH 5/5] Add benchmark script --- benchmark.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 5 ++++- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 benchmark.js diff --git a/benchmark.js b/benchmark.js new file mode 100644 index 00000000..13a78c2f --- /dev/null +++ b/benchmark.js @@ -0,0 +1,44 @@ +var jsdom = require("jsdom"); +global.document = jsdom.jsdom(''); +global.window = document.defaultView; +global.navigator = window.navigator; + + +var Benchmark = require('benchmark'); +var React = require('react'); +var TestUtils = require("react/addons").addons.TestUtils; +global.assert = require('chai').assert; + +// A super simple DOM ready for React to render into + +var ReactTypeahead = require('./lib/react-typeahead').Typeahead; +var TypeaheadOption = require("./lib/typeahead/option"); + +global.simulateTextInput = function(component, value) { + var node = component.refs.entry; + node.value = value; + TestUtils.Simulate.change(node); + return TestUtils.scryRenderedComponentsWithType(component, TypeaheadOption); +}; + +var props = { + options: [ + "a", + "ab", + "dfe", + ], +}; +global.component = TestUtils.renderIntoDocument(React.createElement(ReactTypeahead, props)); + +console.log("running benchmark"); + +var suite = new Benchmark.Suite(); +suite.add("Filtering options", function() { + var results = simulateTextInput(component, "a"); + assert.equal(results.length, 2); + simulateTextInput(component, ""); +}).on('complete', function() { + console.log(this["0"].stats.mean); +}).run({async: false}); + +console.log("done"); diff --git a/package.json b/package.json index 8dd7a7e4..bdb1af51 100644 --- a/package.json +++ b/package.json @@ -40,12 +40,14 @@ }, "main": "lib/react-typeahead.js", "devDependencies": { + "benchmark": "^1.0.0", "browserify": "^8.0.2", "chai": "^1.9.1", "es5-shim": "^4.0.1", "gulp": "^3.8.7", "gulp-mocha-phantomjs": "^0.8.1", "gulp-react": "^3.0.1", + "jsdom": "^7.2.1", "literalify": "^0.4.0", "lodash": "^2.4.1", "mocha": "^1.21.4", @@ -61,7 +63,8 @@ "build": "browserify ./src/react-typeahead.js -t reactify -t literalify -x react -s ReactTypeahead -o ./dist/react-typeahead.js", "watchify": "watchify ./src/react-typeahead.js -t reactify -t literalify -x react -s ReactTypeahead -o ./dist/react-typeahead.js", "lib": "gulp build", - "prepublish": "npm run lib" + "prepublish": "npm run lib", + "benchmark": "node ./benchmark.js" }, "literalify": { "react": "window.React || require('react')"