diff --git a/src/components/dropdown/Dropdown.js b/src/components/dropdown/Dropdown.js index bfd72f69df..c4d0207025 100644 --- a/src/components/dropdown/Dropdown.js +++ b/src/components/dropdown/Dropdown.js @@ -14,7 +14,12 @@ export class Dropdown extends Component { style: null, className: null, autoWidth: true, - scrollHeight: '200px' + scrollHeight: '200px', + filter:false, + filterBy:null, + filterPlaceholder:null, + editable:false, + placeholder:null }; static propTypes = { @@ -25,13 +30,24 @@ export class Dropdown extends Component { style: PropTypes.object, className: PropTypes.string, autoWidth: PropTypes.bool, - scrollHeight: PropTypes.string + scrollHeight: PropTypes.string, + filter:PropTypes.bool, + filterBy: PropTypes.string, + filterPlaceholder: PropTypes.string, + editable:PropTypes.bool, + placeholder: PropTypes.string }; constructor(props) { super(props); this.state = {focus: false}; this.onClick = this.onClick.bind(this); + this.onFilterInputClick=this.onFilterInputClick.bind(this) + this.onInputBlur=this.onInputBlur.bind(this); + this.onInputFocus=this.onInputFocus.bind(this); + this.onKeydown=this.onKeydown.bind(this); + this.onEditableInputClick=this.onEditableInputClick.bind(this); + this.onEditableInputFocus=this.onEditableInputFocus.bind(this); } componentDidMount() { @@ -49,28 +65,28 @@ export class Dropdown extends Component { if(this.documentClickListener) { document.removeEventListener('click', this.documentClickListener); } - } + } onDocumentClick() { - if(!this.selfClick&&!this.itemClick) { + if(!this.selfClick&&!this.itemClick && !this.filterClick) { this.hide(); } - + this.filterClick=false; this.selfClick = false; this.optionClick = false; } onOptionClick(event, option, index) { this.optionClick = true; - this.highlightOption = option; - this.selectItem(event, option, index); + this.highlightOption=option; + this.selectItem(event, option, index); this.hide(); this.input.focus(); event.preventDefault(); } selectItem(event, option, index) { - if(!DomHandler.hasClass(event.target,'ui-state-highlight')) { + if(this.findSelectedOption()!==option){ this.props.onChange({ originalEvent: event, value: option.value, @@ -79,7 +95,7 @@ export class Dropdown extends Component { } } - onClick() { + onClick(event) { if(this.props.disabled) { return; } @@ -87,11 +103,22 @@ export class Dropdown extends Component { this.selfClick = true; if(!this.optionClick) { - this.input.focus(); - if(this.panel.offsetParent) + if(this.props.filter){ + this.filterInput.focus(); + } + + if(this.panel.offsetParent){ + this.input.focus(); this.hide(); - else + } + else { this.show(); + if (this.props.filter) { + setTimeout(() => { + this.filterInput.focus(); + }, 200); + } + } } } @@ -105,7 +132,7 @@ export class Dropdown extends Component { } } } - + return selectedOption; } @@ -115,7 +142,9 @@ export class Dropdown extends Component { DomHandler.relativePosition(this.panel, this.container); DomHandler.fadeIn(this.panel, 250); this.panel.style.display = 'block'; + this.bindDocumentClickListener(); } + this.input.focus(); } hide() { @@ -125,7 +154,7 @@ export class Dropdown extends Component { onInputFocus(event) { this.setState({focus: true}); } - + onInputBlur(event) { this.setState({focus: false}); } @@ -144,7 +173,7 @@ export class Dropdown extends Component { } onKeydown(event) { - let highlightItemIndex = this.highlightOption ? this.findOptionIndex(this.highlightOption) : 0; + let highlightItemIndex =this.highlightOption? this.findOptionIndex(this.highlightOption):0; switch(event.which) { //down @@ -196,6 +225,11 @@ export class Dropdown extends Component { event.preventDefault(); break; + //tab + case 9: + this.hide(); + break; + //space case 32: if(this.panel.style.display==='block') { @@ -209,13 +243,70 @@ export class Dropdown extends Component { } event.preventDefault(); break; - default: break; - } this.setState({highlightOption: this.highlightOption}); } + onFilter(event) { + var inputValue = event.target.value.toLowerCase(); + if(inputValue && inputValue.length) { + this.filterValue = inputValue; + this.activateFilter(); + } + else { + this.filterValue = null; + this.setState({filteredOption: this.props.options}) + } + } + + activateFilter() { + var searchFields = this.props.filterBy.split(','); + if(this.props.options && this.props.options.length) { + this.setState({filteredOption: ObjectUtils.filter(this.props.options, searchFields, this.filterValue)}) + } + } + + onFilterInputClick(event){ + this.filterClick=true; + event.stopPropagation(); + } + bindDocumentClickListener() { + if(!this.documentClickListener) { + this.documentClickListener = document.addEventListener('click', () => { + if(!this.selfClick&&!this.itemClick) { + this.panel.style.display = 'none'; + this.unbindDocumentClickListener(); + } + + this.selfClick = false; + this.itemClick = false; + }); + } + } + unbindDocumentClickListener() { + if(this.documentClickListener) { + this.documentClickListener(); + this.documentClickListener = null; + } + } + onEditableInputFocus(event) { + this.setState({focus:true}); + this.hide(); + } + + onEditableInputClick(event) { + this.optionClick = false; + event.stopPropagation(); + } + + onEditable(event){ + this.editValue=event.target.value; + this.props.onChange({ + originalEvent: event, + value: this.editValue + }); + } render() { var styleClass = classNames('ui-dropdown ui-widget ui-state-default ui-corner-all', this.props.className, { @@ -226,41 +317,64 @@ export class Dropdown extends Component { var selectedOption = this.findSelectedOption(); var label = selectedOption ? selectedOption.label : (this.props.options ? this.props.options[0].label : null); var listItems, optionElements; + var filterInput,filter; + var editable; if(this.props.options) { - listItems = this.props.options.map((option, index) => { - var listItemContent = this.props.itemTemplate ? this.props.itemTemplate(option) : option.label; - var selected = (this.props.value != null && this.props.value === option.value) || (this.props.value == null && index === 0) || this.state.highlightOption === option; - var listItemStyleClass = classNames('ui-dropdown-item ui-corner-all', {'ui-state-highlight': selected}); - var listItem =
Dropdown requires a collection of options with label-value pairs and an onChange event to provide the selected value.
-Options can be filtered using an input field in the overlay by enabling the filter property. By default filtering is done against + label of the SelectItem and filterBy property is available to choose one or more properties of the SelectItem API.
+Label of an option is used as the display text of an item by default, for custom content support define an itemTemplate fucntion that gets the SelectItem as a property and returns the content.
-Name | -Type | -Default | -Description | -
---|---|---|---|
Name | +Type | +Default | +Description | +
value | -any | -null | -Value of the component. | -
options | -array | -null | -An array of selectitems to display as the available options. | -
scrollHeight | -string | -200px | -Height of the viewport in pixels, a scrollbar is defined if height of list exceeds this value. | -
style | -string | -null | -Inline style of the element. | -
className | -string | -null | -Style class of the element. | -
autoWidth | -boolean | -true | -Calculates the width based on options width, set to false for custom width. | -
itemTemplate | -function | -null | -Function that gets the option and returns the content for it. | -
value | +any | +null | +Value of the component. | +
options | +array | +null | +An array of selectitems to display as the available options. | +
scrollHeight | +string | +200px | +Height of the viewport in pixels, a scrollbar is defined if height of list exceeds this value. | +
style | +string | +null | +Inline style of the element. | +
className | +string | +null | +Style class of the element. | +
autoWidth | +boolean | +true | +Calculates the width based on options width, set to false for custom width. | +
itemTemplate | +function | +null | +Function that gets the option and returns the content for it. | +
filter | +boolean | +false | +When specified, displays an input field to filter the items on keyup. | +
filterBy | +string | +null | +When filtering is enabled, filterBy decides which field or fields (comma separated) to search against. | +
filterPlaceholder | +string | +null | +Placeholder text to show when filter input is empty. | +
editable | +boolean | +false | +When present, custom value instead of predefined options can be entered using the editable input field. | +
placeholder | +string | +null | +Default text to display when no option is selected. | +
Name | -Element | -
---|---|
Name | +Element | +
ui-dropdown | -Container element. | -
ui-dropdown-label | -Element to display label of selected option. | -
ui-dropdown-trigger | -Icon element. | -
ui-dropdown-panel | -Icon element. | -
ui-dropdown-items-wrapper | -Wrapper element of items list. | -
ui-dropdown-items | -List element of items. | -
ui-dropdown-item | -An item in the list. | -
ui-dropdown-filter-container | -Container of filter input. | -
ui-dropdown-filter | -Filter element. | -
ui-dropdown-open | -Container element when overlay is visible. | -
ui-dropdown | +Container element. | +
ui-dropdown-label | +Element to display label of selected option. | +
ui-dropdown-trigger | +Icon element. | +
ui-dropdown-panel | +Icon element. | +
ui-dropdown-items-wrapper | +Wrapper element of items list. | +
ui-dropdown-items | +List element of items. | +
ui-dropdown-item | +An item in the list. | +
ui-dropdown-filter-container | +Container of filter input. | +
ui-dropdown-filter | +Filter element. | +
ui-dropdown-open | +Container element when overlay is visible. | +