diff --git a/src/components/dropdown/Dropdown.vue b/src/components/dropdown/Dropdown.vue
index 3403a59ab..678efd727 100755
--- a/src/components/dropdown/Dropdown.vue
+++ b/src/components/dropdown/Dropdown.vue
@@ -7,9 +7,7 @@
-
- {{label}}
-
+ {{label}}
@@ -17,6 +15,7 @@
+
@@ -43,6 +59,7 @@
import {ConnectedOverlayScrollHandler} from 'primevue/utils';
import {ObjectUtils} from 'primevue/utils';
import {DomHandler} from 'primevue/utils';
+import {FilterService} from 'primevue/api';
import Ripple from 'primevue/ripple';
export default {
@@ -53,6 +70,8 @@ export default {
optionLabel: null,
optionValue: null,
optionDisabled: null,
+ optionGroupLabel: null,
+ optionGroupChildren: null,
scrollHeight: {
type: String,
default: '200px'
@@ -60,6 +79,14 @@ export default {
filter: Boolean,
filterPlaceholder: String,
filterLocale: String,
+ filterMatchMode: {
+ type: String,
+ default: 'contains'
+ },
+ filterFields: {
+ type: Array,
+ default: null
+ },
editable: Boolean,
placeholder: String,
disabled: Boolean,
@@ -74,7 +101,11 @@ export default {
},
emptyFilterMessage: {
type: String,
- default: 'No results found'
+ default: null
+ },
+ emptyMessage: {
+ type: String,
+ default: null
}
},
data() {
@@ -116,37 +147,48 @@ export default {
isOptionDisabled(option) {
return this.optionDisabled ? ObjectUtils.resolveFieldData(option, this.optionDisabled) : false;
},
+ getOptionGroupRenderKey(optionGroup) {
+ return ObjectUtils.resolveFieldData(optionGroup, this.optionGroupLabel);
+ },
+ getOptionGroupLabel(optionGroup) {
+ return ObjectUtils.resolveFieldData(optionGroup, this.optionGroupLabel);
+ },
+ getOptionGroupChildren(optionGroup) {
+ return ObjectUtils.resolveFieldData(optionGroup, this.optionGroupChildren);
+ },
getSelectedOption() {
- let selectedOption;
-
+ let index = this.getSelectedOptionIndex();
+ return index !== -1 ? (this.optionGroupLabel ? this.getOptionGroupChildren(this.options[index.group])[index.option]: this.options[index]) : null;
+ },
+ getSelectedOptionIndex() {
if (this.modelValue != null && this.options) {
- for (let option of this.options) {
- if ((ObjectUtils.equals(this.modelValue, this.getOptionValue(option), this.equalityKey))) {
- selectedOption = option;
- break;
+ if (this.optionGroupLabel) {
+ for (let i = 0; i < this.options.length; i++) {
+ let selectedOptionIndex = this.findOptionIndexInList(this.modelValue, this.getOptionGroupChildren(this.options[i]));
+ if (selectedOptionIndex !== -1) {
+ return {group: i, option: selectedOptionIndex};
+ }
}
}
+ else {
+ return this.findOptionIndexInList(this.modelValue, this.options);
+ }
+ }
+
+ return -1;
+ },
+ findOptionIndexInList(value, list) {
+ for (let i = 0; i < list.length; i++) {
+ if ((ObjectUtils.equals(value, this.getOptionValue(list[i]), this.equalityKey))) {
+ return i;
+ }
}
- return selectedOption;
+ return -1;
},
isSelected(option) {
return ObjectUtils.equals(this.modelValue, this.getOptionValue(option), this.equalityKey);
},
- getSelectedOptionIndex() {
- let selectedOptionIndex = -1;
-
- if (this.modelValue != null && this.visibleOptions) {
- for (let i = 0; i < this.visibleOptions.length; i++) {
- if ((ObjectUtils.equals(this.modelValue, this.getOptionValue(this.visibleOptions[i]), this.equalityKey))) {
- selectedOptionIndex = i;
- break;
- }
- }
- }
-
- return selectedOptionIndex;
- },
show() {
this.$emit('before-show');
this.overlayVisible = true;
@@ -230,7 +272,6 @@ export default {
}
else {
let nextOption = this.findNextOption(this.getSelectedOptionIndex());
-
if (nextOption) {
this.updateModel(event, this.getOptionValue(nextOption));
}
@@ -242,7 +283,6 @@ export default {
onUpKey(event) {
if (this.visibleOptions) {
let prevOption = this.findPrevOption(this.getSelectedOptionIndex());
-
if (prevOption) {
this.updateModel(event, this.getOptionValue(prevOption));
}
@@ -251,25 +291,62 @@ export default {
event.preventDefault();
},
findNextOption(index) {
- let i = index + 1;
- if (i === this.visibleOptions.length) {
+ if (this.optionGroupLabel) {
+ let groupIndex = index === -1 ? 0 : index.group;
+ let optionIndex = index === -1 ? -1 : index.option;
+ let option = this.findNextOptionInList(this.getOptionGroupChildren(this.visibleOptions[groupIndex]), optionIndex);
+
+ if (option)
+ return option;
+ else if ((groupIndex + 1) !== this.visibleOptions.length)
+ return this.findNextOption({group: (groupIndex + 1), option: -1});
+ else
+ return null;
+ }
+ else {
+ return this.findNextOptionInList(this.visibleOptions, index);
+ }
+ },
+ findNextOptionInList(list, index) {
+ let i = index + 1;
+ if (i === list.length) {
+ return null;
+ }
+
+ let option = list[i];
+ if (this.isOptionDisabled(option))
+ return this.findNextOptionInList(i);
+ else
+ return option;
+ },
+ findPrevOption(index) {
+ if (index === -1) {
return null;
}
- let option = this.visibleOptions[i];
- if (this.isOptionDisabled(option))
- return this.findNextOption(i);
- else
- return option;
+ if (this.optionGroupLabel) {
+ let groupIndex = index.group;
+ let optionIndex = index.option;
+ let option = this.findPrevOptionInList(this.getOptionGroupChildren(this.visibleOptions[groupIndex]), optionIndex);
+ if (option)
+ return option;
+ else if (groupIndex > 0)
+ return this.findPrevOption({group: (groupIndex - 1), option: this.getOptionGroupChildren(this.visibleOptions[groupIndex - 1]).length});
+ else
+ return null;
+ }
+ else {
+ return this.findPrevOptionInList(this.visibleOptions, index);
+ }
},
- findPrevOption(index) {
+ findPrevOptionInList(list, index) {
let i = index - 1;
if (i < 0) {
return null;
}
- let option = this.visibleOptions[i];
+ let option = list[i];
if (this.isOptionDisabled(option))
return this.findPrevOption(i);
else
@@ -406,13 +483,14 @@ export default {
else
this.searchValue = this.searchValue ? this.searchValue + char : char;
- let searchIndex = this.getSelectedOptionIndex();
- let newOption = this.searchOption(++searchIndex);
-
- if (newOption) {
- this.updateModel(event, this.getOptionValue(newOption));
+ if (this.searchValue) {
+ let searchIndex = this.getSelectedOptionIndex();
+ let newOption = this.optionGroupLabel ? this.searchOptionInGroup(searchIndex) : this.searchOption(++searchIndex);
+ if (newOption) {
+ this.updateModel(event, this.getOptionValue(newOption));
+ }
}
-
+
this.searchTimeout = setTimeout(() => {
this.searchValue = null;
}, 250);
@@ -433,14 +511,40 @@ export default {
searchOptionInRange(start, end) {
for (let i = start; i < end; i++) {
let opt = this.visibleOptions[i];
- let label = this.getOptionLabel(opt).toLocaleLowerCase(this.filterLocale);
- if (label.startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale))) {
+ if (this.matchesSearchValue(opt)) {
return opt;
}
}
return null;
},
+ searchOptionInGroup(index) {
+ let searchIndex = index === -1 ? {group: 0, option: -1} : index;
+
+ for (let i = searchIndex.group; i < this.visibleOptions.length; i++) {
+ let groupOptions = this.getOptionGroupChildren(this.visibleOptions[i]);
+ for (let j = (searchIndex.group === i ? searchIndex.option + 1 : 0); j < groupOptions.length; j++) {
+ if (this.matchesSearchValue(groupOptions[j])) {
+ return groupOptions[j];
+ }
+ }
+ }
+
+ for (let i = 0; i <= searchIndex.group; i++) {
+ let groupOptions = this.getOptionGroupChildren(this.visibleOptions[i]);
+ for (let j = 0; j < (searchIndex.group === i ? searchIndex.option: groupOptions.length); j++) {
+ if (this.matchesSearchValue(groupOptions[j])) {
+ return groupOptions[j];
+ }
+ }
+ }
+
+ return null;
+ },
+ matchesSearchValue(option) {
+ let label = this.getOptionLabel(option).toLocaleLowerCase(this.filterLocale);
+ return label.startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale));
+ },
appendContainer() {
if (this.appendTo) {
if (this.appendTo === 'body')
@@ -469,10 +573,24 @@ export default {
},
computed: {
visibleOptions() {
- if (this.filterValue && this.filterValue.trim().length > 0)
- return this.options.filter(option => this.getOptionLabel(option).toLocaleLowerCase(this.filterLocale).indexOf(this.filterValue.toLocaleLowerCase(this.filterLocale)) > -1);
- else
+ if (this.filterValue) {
+ if (this.optionGroupLabel) {
+ let filteredGroups = [];
+ for (let optgroup of this.options) {
+ let filteredSubOptions = FilterService.filter(this.getOptionGroupChildren(optgroup), this.searchFields, this.filterValue, this.filterMatchMode, this.filterLocale);
+ if (filteredSubOptions && filteredSubOptions.length) {
+ filteredGroups.push({...optgroup, ...{items: filteredSubOptions}});
+ }
+ }
+ return filteredGroups
+ }
+ else {
+ return FilterService.filter(this.options, this.searchFields, this.filterValue, 'contains', this.filterLocale);
+ }
+ }
+ else {
return this.options;
+ }
},
containerClass() {
return [
@@ -511,6 +629,15 @@ export default {
},
equalityKey() {
return this.optionValue ? null : this.dataKey;
+ },
+ searchFields() {
+ return this.filterFields || [this.optionLabel];
+ },
+ emptyFilterMessageText() {
+ return this.emptyFilterMessage || this.$primevue.config.locale.emptyFilterMessage;
+ },
+ emptyMessageText() {
+ return this.emptyMessage || this.$primevue.config.locale.emptyMessage;
}
},
directives: {