diff --git a/src/components/multiselect/MultiSelect.d.ts b/src/components/multiselect/MultiSelect.d.ts index 9e9fcb816f..82c57e913b 100755 --- a/src/components/multiselect/MultiSelect.d.ts +++ b/src/components/multiselect/MultiSelect.d.ts @@ -17,6 +17,7 @@ interface MultiSelectProps { tooltip?: any; tooltipOptions?: TooltipOptions; itemTemplate?(item: any): JSX.Element | undefined; + selectedOptionTemplate?(item: any): JSX.Element | undefined; onChange?(e: {originalEvent: Event, value: any}): void; } diff --git a/src/components/multiselect/MultiSelect.js b/src/components/multiselect/MultiSelect.js index e42766673c..1783e24abe 100644 --- a/src/components/multiselect/MultiSelect.js +++ b/src/components/multiselect/MultiSelect.js @@ -26,6 +26,7 @@ export class MultiSelect extends Component { tooltip: null, tooltipOptions: null, itemTemplate: null, + selectedOptionTemplate: null, onChange: null }; @@ -45,6 +46,7 @@ export class MultiSelect extends Component { tooltip: PropTypes.string, tooltipOptions: PropTypes.object, itemTemplate: PropTypes.func, + selectedOptionTemplate: PropTypes.func, onChange: PropTypes.func, }; @@ -204,7 +206,7 @@ export class MultiSelect extends Component { getLabel() { let label; - + if(this.props.value && this.props.value.length) { label = ''; for(let i = 0; i < this.props.value.length; i++) { @@ -223,35 +225,51 @@ export class MultiSelect extends Component { findLabelByValue(val) { let label = null; - + for(let i = 0; i < this.props.options.length; i++) { let option = this.props.options[i]; let optionValue = this.getOptionValue(option); - + if(ObjectUtils.equals(optionValue, val)) { label = this.getOptionLabel(option); - break; + break; } } - + return label; } + findOptionByValue(val) { + let option = null; + + for(let i = 0; i < this.props.options.length; i++) { + let opt = this.props.options[i]; + let optionValue = this.getOptionValue(opt); + + if(ObjectUtils.equals(optionValue, val)) { + option = opt; + break; + } + } + + return option; + } + onFocus() { DomHandler.addClass(this.container, 'p-focus'); } - + onBlur() { DomHandler.removeClass(this.container, 'p-focus'); } - + bindDocumentClickListener() { if(!this.documentClickListener) { this.documentClickListener = this.onDocumentClick.bind(this); document.addEventListener('click', this.documentClickListener); } } - + unbindDocumentClickListener() { if(this.documentClickListener) { document.removeEventListener('click', this.documentClickListener); @@ -287,43 +305,43 @@ export class MultiSelect extends Component { if(!this.selfClick && !this.panelClick && this.panel.element.offsetParent) { this.hide(); } - + this.clearClickState(); } - + clearClickState() { this.selfClick = false; this.panelClick = false; } - + filterOption(option) { let filterValue = this.state.filter.trim().toLowerCase(); let optionLabel = this.getOptionLabel(option); - + return optionLabel.toLowerCase().indexOf(filterValue.toLowerCase()) > -1; } - + hasFilter() { return this.state.filter && this.state.filter.trim().length > 0; } - + isAllChecked(visibleOptions) { if(this.hasFilter()) return this.props.value && visibleOptions && visibleOptions.length&&(this.props.value.length === visibleOptions.length); else return this.props.value && this.props.options && (this.props.value.length === this.props.options.length); - } - + } + filterOptions(options) { return options.filter((option) => { return this.filterOption(option); }); } - + getOptionValue(option) { return this.props.optionLabel ? option : option.value; } - + getOptionLabel(option) { return this.props.optionLabel ? ObjectUtils.resolveFieldData(option, this.props.optionLabel) : option.label; } @@ -343,11 +361,29 @@ export class MultiSelect extends Component { ); } + renderLabel() { + if(this.props.selectedOptionTemplate) { + if(this.props.value && this.props.value.length) { + return this.props.value.map((val, index) => { + return {this.props.selectedOptionTemplate(this.findOptionByValue(val))}; + }); + } + else { + return this.props.selectedOptionTemplate(); + } + } + else { + return this.getLabel(); + } + } + render() { let className = classNames('p-multiselect p-component', this.props.className, { 'p-disabled': this.props.disabled }); - let label = this.getLabel(); + + let label = this.renderLabel(); + let items = this.props.options; if (items) { diff --git a/src/sass/App.scss b/src/sass/App.scss index 321ed3144a..0642d3acfb 100644 --- a/src/sass/App.scss +++ b/src/sass/App.scss @@ -1284,6 +1284,29 @@ pre[class*="language-"] { } } +/*MultiSelect */ +.multiselect-demo { + .my-multiselected-item-token, .my-multiselected-empty-token { + padding: 2px 4px; + margin: 0 0.286em 0 0; + display: inline-block; + vertical-align:middle; + height: 1.857em; + border-radius: 3px; + } + + .my-multiselected-item-token { + background: #007ad9; + color: #ffffff; + } + + .my-multiselected-empty-token { + background: #d95f00; + color: #ffffff; + } + +} + /* Responsive Tables */ .p-col-d { display: table-cell; diff --git a/src/showcase/multiselect/MultiSelectDemo.js b/src/showcase/multiselect/MultiSelectDemo.js index f7ee536edc..3a9fe49d5d 100644 --- a/src/showcase/multiselect/MultiSelectDemo.js +++ b/src/showcase/multiselect/MultiSelectDemo.js @@ -9,8 +9,36 @@ export class MultiSelectDemo extends Component { constructor() { super(); this.state = { - cars: [] + cars1: [], + cars2: [] }; + this.carTemplate = this.carTemplate.bind(this); + this.selectedCarTemplate = this.selectedCarTemplate.bind(this); + } + carTemplate(option) { + const logoPath = 'showcase/resources/demo/images/car/' + option.label + '.png'; + + return ( +
+ {option.label} + {option.label} +
+ ); + } + selectedCarTemplate(option) { + + if(option) { + const logoPath = 'showcase/resources/demo/images/car/' + option.label + '.png'; + return ( +
+ {option.label} + {option.label} +
+ ); + } + else { + return Choose + } } render() { @@ -35,9 +63,15 @@ export class MultiSelectDemo extends Component { -
- this.setState({cars: e.value})} - style={{width:'12em'}} filter={true} /> +
+

Basic

+ this.setState({cars1: e.value})} + style={{minWidth:'12em'}} filter={true}/> + + +

Templating

+ this.setState({cars2: e.value})} + style={{minWidth:'12em'}} filter={true} itemTemplate={this.carTemplate} selectedOptionTemplate={this.selectedCarTemplate}/>
@@ -138,6 +172,36 @@ carTemplate(option) { `} +

In addition selectedOptionTemplate can be used to customize the selected values display instead of the default comma separated list.

+ + + {` + this.setState({cars: e.value})} selectedOptionTemplate={this.selectedCarTemplate} /> + +`} + + + + {` + +selectedCarTemplate(option) { + + if(option) { + const logoPath = 'showcase/resources/demo/images/car/' + option.label + '.png'; + return ( +
+ {option.label} + {option.label} +
+ ); + } + else { + return Choose + } +} + +`} +

Filter

Filtering allows searching items in the list using an input field at the header. In order to use filtering, enable filter property.

@@ -245,6 +309,12 @@ carTemplate(option) { null Function that gets the option and returns the content for it. + + selectedOptionTemplate + function + null + Function that gets the option and returns the content for selected option. + appendTo DOM element