diff --git a/src/Select.jsx b/src/Select.jsx index 84be11b9d..e04442c8d 100644 --- a/src/Select.jsx +++ b/src/Select.jsx @@ -26,7 +26,7 @@ function saveRef(name, component) { } function chaining(...fns) { - return function (...args) { + return function (...args) { // eslint-disable-line for (let i = 0; i < fns.length; i++) { if (fns[i] && typeof fns[i] === 'function') { fns[i].apply(this, args); @@ -716,13 +716,9 @@ const Select = createClass({ return; } let { open } = this.state; - if (typeof document !== 'undefined' && - this.getInputDOMNode() && - document.activeElement === this.getInputDOMNode()) { - open = true; - } let options = []; - if (open) { + // If hidden menu due to no options, then it should be calculated again + if (open || this.hiddenForNoOptions) { options = this.renderFilterOptions(); } this._options = options; @@ -730,6 +726,12 @@ const Select = createClass({ if (isMultipleOrTagsOrCombobox(this.props) || !this.props.showSearch) { if (open && !options.length) { open = false; + this.hiddenForNoOptions = true; + } + // Keep menu open if there are options and hidden for no options before + if (this.hiddenForNoOptions && options.length) { + open = true; + this.hiddenForNoOptions = false; } } this.state.open = open; diff --git a/tests/Select.combobox.spec.js b/tests/Select.combobox.spec.js index 2a83e277a..651dbd660 100644 --- a/tests/Select.combobox.spec.js +++ b/tests/Select.combobox.spec.js @@ -1,9 +1,11 @@ -/* eslint-disable no-undef */ +/* eslint-disable no-undef, react/no-multi-comp */ import React from 'react'; import Select, { Option } from '../src'; import { mount, render } from 'enzyme'; import allowClearTest from './shared/allowClearTest'; +const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout)); + describe('Select.combobox', () => { allowClearTest('combobox'); @@ -112,5 +114,85 @@ describe('Select.combobox', () => { expect(wrapper.find('input').props().value).toBe('One'); }); }); + + describe('hidden when filtered options is empty', () => { + // https://github.com/ant-design/ant-design/issues/3958 + it('should popup when input with async data', () => { + class AsyncCombobox extends React.Component { + state = { + data: [], + } + handleChange = () => { + setTimeout(() => { + this.setState({ + data: [{ key: '1', label: '1' }, { key: '2', label: '2' }], + }); + }, 500); + } + render() { + const options = this.state.data.map(item => ( + + )); + return ( + + ); + } + } + const wrapper = mount(); + wrapper.find('input').simulate('focus'); + wrapper.find('input').simulate('change', { target: { value: '0' } }); + return delay(1000).then(() => { + expect(wrapper.find('.rc-select-dropdown') + .hasClass('rc-select-dropdown-hidden')).toBe(false); + }); + }); + + // https://github.com/ant-design/ant-design/issues/6600 + it('should not repop menu after select', () => { + class AsyncCombobox extends React.Component { + state = { + data: [{ key: '1', label: '1' }, { key: '2', label: '2' }], + } + onSelect = () => { + setTimeout(() => { + this.setState({ + data: [{ key: '3', label: '3' }, { key: '4', label: '4' }], + }); + }, 500); + } + render() { + const options = this.state.data.map(item => ( + + )); + return ( + + ); + } + } + const wrapper = mount(); + wrapper.find('input').simulate('focus'); + wrapper.find('input').simulate('change', { target: { value: '0' } }); + expect(wrapper.find('.rc-select-dropdown') + .hasClass('rc-select-dropdown-hidden')).toBe(false); + wrapper.find('MenuItem').first().simulate('click'); + return delay(1000).then(() => { + expect(wrapper.find('.rc-select-dropdown').length).toBe(0); + }); + }); + }); }); }); diff --git a/tests/__mocks__/rc-trigger.js b/tests/__mocks__/rc-trigger.js index ff9788d40..2e8d052a1 100644 --- a/tests/__mocks__/rc-trigger.js +++ b/tests/__mocks__/rc-trigger.js @@ -4,7 +4,7 @@ const Trigger = require.requireActual('rc-trigger'); const render = Trigger.prototype.render; -Trigger.prototype.render = function () { +Trigger.prototype.render = function () { // eslint-disable-line const { popupVisible } = this.state; return (