diff --git a/docs/Props.md b/docs/Props.md index ed3f7511..8fc3da29 100644 --- a/docs/Props.md +++ b/docs/Props.md @@ -36,6 +36,7 @@ renderMenu | function | | Callback for custom menu rendering. renderMenuItemChildren | function | | Provides a hook for customized rendering of menu item contents. renderToken | function | | Provides a hook for customized rendering of tokens when multiple selections are enabled. selected | array | `[]` | The selected option(s) displayed in the input. Use this prop if you want to control the component via its parent. +submitFormOnEnter | boolean | false | Propagate event to parent form. ### `` Name | Type | Default | Description diff --git a/src/Typeahead.react.js b/src/Typeahead.react.js index 80c37f4f..e316b4f1 100644 --- a/src/Typeahead.react.js +++ b/src/Typeahead.react.js @@ -142,6 +142,11 @@ const Typeahead = React.createClass({ * to control the component via its parent. */ selected: PropTypes.array, + + /** + * Propagate to parent form + */ + submitFormOnEnter: PropTypes.bool, }, getDefaultProps() { @@ -167,6 +172,7 @@ const Typeahead = React.createClass({ onPaginate: noop, paginate: true, selected: [], + submitFormOnEnter: false, }; }, @@ -540,11 +546,15 @@ const Typeahead = React.createClass({ this._hideDropdown(); break; case RETURN: - // Prevent submitting forms. - e.preventDefault(); + // if menu is shown and we have active item + // there is no any sense to submit form on + if (!this.props.submitFormOnEnter || showMenu && activeItem) { + // Prevent submitting forms. + e.preventDefault(); + } - if (showMenu) { - activeItem && this._handleAddOption(activeItem); + if (showMenu && activeItem) { + this._handleAddOption(activeItem); } break; } diff --git a/test/TypeaheadSpec.js b/test/TypeaheadSpec.js index b9c2b84f..0260ed5b 100644 --- a/test/TypeaheadSpec.js +++ b/test/TypeaheadSpec.js @@ -6,6 +6,7 @@ import ReactTestUtils from 'react-addons-test-utils'; import TokenizerInput from '../src/TokenizerInput'; import Typeahead from '../src/Typeahead'; import TypeaheadInput from '../src/TypeaheadInput'; +import {RETURN} from '../src/utils/keyCode'; import states from '../example/exampleData'; @@ -33,6 +34,20 @@ function getTypeaheadInstance(props) { return ReactTestUtils.renderIntoDocument(); } +class FormWrapper extends React.Component { + render() { + return ( +
+ + + ); + } +} + +function getFormWithTypeaheadInstance(props) { + return ReactTestUtils.renderIntoDocument(); +} + describe('', () => { it('should have a TypeaheadInput', () => { @@ -214,4 +229,50 @@ describe('', () => { expect(InputNode).to.exist; }); + describe('form integration', () => { + let onKeyDownEvent = null; + const onKeyDown = evt => onKeyDownEvent = evt; + + beforeEach(() => { + onKeyDownEvent = null; + }); + + /** + * since react test simulation doesn't trigger form submit + * on RETURN press, we should handle key down event on form level + * and test whether default was prevented or not + */ + it('should not submit form when `submitFormOnEnter=false', () => { + const instance = getFormWithTypeaheadInstance({ + ...baseProps, + submitFormOnEnter: false, + onKeyDown, + }); + + const inputNode = getInputNode(instance); + ReactTestUtils.Simulate.focus(inputNode); + ReactTestUtils.Simulate.keyDown(inputNode, { + key: 'Enter', keyCode: RETURN, which: RETURN, + }); + + expect(onKeyDownEvent).to.have.property('defaultPrevented', true); + }); + + it('should submit form when `submitFormOnEnter=true', () => { + const instance = getFormWithTypeaheadInstance({ + ...baseProps, + submitFormOnEnter: true, + onKeyDown, + }); + + const inputNode = getInputNode(instance); + ReactTestUtils.Simulate.focus(inputNode); + ReactTestUtils.Simulate.keyDown(inputNode, { + key: 'Enter', keyCode: RETURN, which: RETURN, + }); + + expect(onKeyDownEvent).to.have.property('defaultPrevented', undefined); + }); + }); + });