Add form support to `Listbox`
parent
044a900f9d
commit
1802fcda9d
|
@ -1,12 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import BaseComponent from '@primevue/core/basecomponent';
|
import BaseEditableHolder from '@primevue/core/baseeditableholder';
|
||||||
import ListboxStyle from 'primevue/listbox/style';
|
import ListboxStyle from 'primevue/listbox/style';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'BaseListbox',
|
name: 'BaseListbox',
|
||||||
extends: BaseComponent,
|
extends: BaseEditableHolder,
|
||||||
props: {
|
props: {
|
||||||
modelValue: null,
|
|
||||||
options: Array,
|
options: Array,
|
||||||
optionLabel: null,
|
optionLabel: null,
|
||||||
optionValue: null,
|
optionValue: null,
|
||||||
|
@ -18,14 +17,6 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: '14rem'
|
default: '14rem'
|
||||||
},
|
},
|
||||||
invalid: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
dataKey: null,
|
dataKey: null,
|
||||||
multiple: {
|
multiple: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
:data-p-hidden-focusable="true"
|
:data-p-hidden-focusable="true"
|
||||||
></span>
|
></span>
|
||||||
<div v-if="$slots.header" :class="cx('header')">
|
<div v-if="$slots.header" :class="cx('header')">
|
||||||
<slot name="header" :value="modelValue" :options="visibleOptions"></slot>
|
<slot name="header" :value="d_value" :options="visibleOptions"></slot>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="filter" :class="cx('header')" v-bind="ptm('header')">
|
<div v-if="filter" :class="cx('header')" v-bind="ptm('header')">
|
||||||
<IconField :unstyled="unstyled" :pt="ptm('pcFilterContainer')">
|
<IconField :unstyled="unstyled" :pt="ptm('pcFilterContainer')">
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
</template>
|
</template>
|
||||||
</VirtualScroller>
|
</VirtualScroller>
|
||||||
</div>
|
</div>
|
||||||
<slot name="footer" :value="modelValue" :options="visibleOptions"></slot>
|
<slot name="footer" :value="d_value" :options="visibleOptions"></slot>
|
||||||
<span v-if="!options || (options && options.length === 0)" role="status" aria-live="polite" class="p-hidden-accessible" v-bind="ptm('hiddenEmptyMessage')" :data-p-hidden-accessible="true">
|
<span v-if="!options || (options && options.length === 0)" role="status" aria-live="polite" class="p-hidden-accessible" v-bind="ptm('hiddenEmptyMessage')" :data-p-hidden-accessible="true">
|
||||||
{{ emptyMessageText }}
|
{{ emptyMessageText }}
|
||||||
</span>
|
</span>
|
||||||
|
@ -150,7 +150,7 @@ export default {
|
||||||
name: 'Listbox',
|
name: 'Listbox',
|
||||||
extends: BaseListbox,
|
extends: BaseListbox,
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
emits: ['update:modelValue', 'change', 'focus', 'blur', 'filter', 'item-dblclick', 'option-dblclick'],
|
emits: ['change', 'focus', 'blur', 'filter', 'item-dblclick', 'option-dblclick'],
|
||||||
list: null,
|
list: null,
|
||||||
virtualScroller: null,
|
virtualScroller: null,
|
||||||
optionTouched: false,
|
optionTouched: false,
|
||||||
|
@ -386,11 +386,11 @@ export default {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
value = metaKey ? this.removeOption(option) : [this.getOptionValue(option)];
|
value = metaKey ? this.removeOption(option) : [this.getOptionValue(option)];
|
||||||
} else {
|
} else {
|
||||||
value = metaKey ? this.modelValue || [] : [];
|
value = metaKey ? this.d_value || [] : [];
|
||||||
value = [...value, this.getOptionValue(option)];
|
value = [...value, this.getOptionValue(option)];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
value = selected ? this.removeOption(option) : [...(this.modelValue || []), this.getOptionValue(option)];
|
value = selected ? this.removeOption(option) : [...(this.d_value || []), this.getOptionValue(option)];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateModel(event, value);
|
this.updateModel(event, value);
|
||||||
|
@ -561,8 +561,8 @@ export default {
|
||||||
isSelected(option) {
|
isSelected(option) {
|
||||||
const optionValue = this.getOptionValue(option);
|
const optionValue = this.getOptionValue(option);
|
||||||
|
|
||||||
if (this.multiple) return (this.modelValue || []).some((value) => this.isEquals(value, optionValue));
|
if (this.multiple) return (this.d_value || []).some((value) => this.isEquals(value, optionValue));
|
||||||
else return this.isEquals(this.modelValue, optionValue);
|
else return this.isEquals(this.d_value, optionValue);
|
||||||
},
|
},
|
||||||
findFirstOptionIndex() {
|
findFirstOptionIndex() {
|
||||||
return this.visibleOptions.findIndex((option) => this.isValidOption(option));
|
return this.visibleOptions.findIndex((option) => this.isValidOption(option));
|
||||||
|
@ -581,10 +581,10 @@ export default {
|
||||||
return matchedOptionIndex > -1 ? matchedOptionIndex : index;
|
return matchedOptionIndex > -1 ? matchedOptionIndex : index;
|
||||||
},
|
},
|
||||||
findSelectedOptionIndex() {
|
findSelectedOptionIndex() {
|
||||||
if (this.hasSelectedOption) {
|
if (this.$filled) {
|
||||||
if (this.multiple) {
|
if (this.multiple) {
|
||||||
for (let index = this.modelValue.length - 1; index >= 0; index--) {
|
for (let index = this.d_value.length - 1; index >= 0; index--) {
|
||||||
const value = this.modelValue[index];
|
const value = this.d_value[index];
|
||||||
const matchedOptionIndex = this.visibleOptions.findIndex((option) => this.isValidSelectedOption(option) && this.isEquals(value, this.getOptionValue(option)));
|
const matchedOptionIndex = this.visibleOptions.findIndex((option) => this.isValidSelectedOption(option) && this.isEquals(value, this.getOptionValue(option)));
|
||||||
|
|
||||||
if (matchedOptionIndex > -1) return matchedOptionIndex;
|
if (matchedOptionIndex > -1) return matchedOptionIndex;
|
||||||
|
@ -597,25 +597,25 @@ export default {
|
||||||
return -1;
|
return -1;
|
||||||
},
|
},
|
||||||
findFirstSelectedOptionIndex() {
|
findFirstSelectedOptionIndex() {
|
||||||
return this.hasSelectedOption ? this.visibleOptions.findIndex((option) => this.isValidSelectedOption(option)) : -1;
|
return this.$filled ? this.visibleOptions.findIndex((option) => this.isValidSelectedOption(option)) : -1;
|
||||||
},
|
},
|
||||||
findLastSelectedOptionIndex() {
|
findLastSelectedOptionIndex() {
|
||||||
return this.hasSelectedOption ? findLastIndex(this.visibleOptions, (option) => this.isValidSelectedOption(option)) : -1;
|
return this.$filled ? findLastIndex(this.visibleOptions, (option) => this.isValidSelectedOption(option)) : -1;
|
||||||
},
|
},
|
||||||
findNextSelectedOptionIndex(index) {
|
findNextSelectedOptionIndex(index) {
|
||||||
const matchedOptionIndex = this.hasSelectedOption && index < this.visibleOptions.length - 1 ? this.visibleOptions.slice(index + 1).findIndex((option) => this.isValidSelectedOption(option)) : -1;
|
const matchedOptionIndex = this.$filled && index < this.visibleOptions.length - 1 ? this.visibleOptions.slice(index + 1).findIndex((option) => this.isValidSelectedOption(option)) : -1;
|
||||||
|
|
||||||
return matchedOptionIndex > -1 ? matchedOptionIndex + index + 1 : -1;
|
return matchedOptionIndex > -1 ? matchedOptionIndex + index + 1 : -1;
|
||||||
},
|
},
|
||||||
findPrevSelectedOptionIndex(index) {
|
findPrevSelectedOptionIndex(index) {
|
||||||
const matchedOptionIndex = this.hasSelectedOption && index > 0 ? findLastIndex(this.visibleOptions.slice(0, index), (option) => this.isValidSelectedOption(option)) : -1;
|
const matchedOptionIndex = this.$filled && index > 0 ? findLastIndex(this.visibleOptions.slice(0, index), (option) => this.isValidSelectedOption(option)) : -1;
|
||||||
|
|
||||||
return matchedOptionIndex > -1 ? matchedOptionIndex : -1;
|
return matchedOptionIndex > -1 ? matchedOptionIndex : -1;
|
||||||
},
|
},
|
||||||
findNearestSelectedOptionIndex(index, firstCheckUp = false) {
|
findNearestSelectedOptionIndex(index, firstCheckUp = false) {
|
||||||
let matchedOptionIndex = -1;
|
let matchedOptionIndex = -1;
|
||||||
|
|
||||||
if (this.hasSelectedOption) {
|
if (this.$filled) {
|
||||||
if (firstCheckUp) {
|
if (firstCheckUp) {
|
||||||
matchedOptionIndex = this.findPrevSelectedOptionIndex(index);
|
matchedOptionIndex = this.findPrevSelectedOptionIndex(index);
|
||||||
matchedOptionIndex = matchedOptionIndex === -1 ? this.findNextSelectedOptionIndex(index) : matchedOptionIndex;
|
matchedOptionIndex = matchedOptionIndex === -1 ? this.findNextSelectedOptionIndex(index) : matchedOptionIndex;
|
||||||
|
@ -669,7 +669,7 @@ export default {
|
||||||
}, 500);
|
}, 500);
|
||||||
},
|
},
|
||||||
removeOption(option) {
|
removeOption(option) {
|
||||||
return this.modelValue.filter((val) => !equals(val, this.getOptionValue(option), this.equalityKey));
|
return this.d_value.filter((val) => !equals(val, this.getOptionValue(option), this.equalityKey));
|
||||||
},
|
},
|
||||||
changeFocusedOptionIndex(event, index) {
|
changeFocusedOptionIndex(event, index) {
|
||||||
if (this.focusedOptionIndex !== index) {
|
if (this.focusedOptionIndex !== index) {
|
||||||
|
@ -694,13 +694,13 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
autoUpdateModel() {
|
autoUpdateModel() {
|
||||||
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption && !this.multiple && this.focused) {
|
if (this.selectOnFocus && this.autoOptionFocus && !this.$filled && !this.multiple && this.focused) {
|
||||||
this.focusedOptionIndex = this.findFirstFocusedOptionIndex();
|
this.focusedOptionIndex = this.findFirstFocusedOptionIndex();
|
||||||
this.onOptionSelect(null, this.visibleOptions[this.focusedOptionIndex]);
|
this.onOptionSelect(null, this.visibleOptions[this.focusedOptionIndex]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateModel(event, value) {
|
updateModel(event, value) {
|
||||||
this.$emit('update:modelValue', value);
|
this.updateValue(value, event);
|
||||||
this.$emit('change', { originalEvent: event, value });
|
this.$emit('change', { originalEvent: event, value });
|
||||||
},
|
},
|
||||||
flatOptions(options) {
|
flatOptions(options) {
|
||||||
|
@ -728,8 +728,9 @@ export default {
|
||||||
|
|
||||||
return this.filterValue ? FilterService.filter(options, this.searchFields, this.filterValue, this.filterMatchMode, this.filterLocale) : options;
|
return this.filterValue ? FilterService.filter(options, this.searchFields, this.filterValue, this.filterMatchMode, this.filterLocale) : options;
|
||||||
},
|
},
|
||||||
|
// @deprecated use $filled instead
|
||||||
hasSelectedOption() {
|
hasSelectedOption() {
|
||||||
return isNotEmpty(this.modelValue);
|
return isNotEmpty(this.d_value);
|
||||||
},
|
},
|
||||||
equalityKey() {
|
equalityKey() {
|
||||||
return this.optionValue ? null : this.dataKey;
|
return this.optionValue ? null : this.dataKey;
|
||||||
|
@ -756,7 +757,7 @@ export default {
|
||||||
return this.emptySelectionMessage || this.$primevue.config.locale.emptySelectionMessage || '';
|
return this.emptySelectionMessage || this.$primevue.config.locale.emptySelectionMessage || '';
|
||||||
},
|
},
|
||||||
selectedMessageText() {
|
selectedMessageText() {
|
||||||
return this.hasSelectedOption ? this.selectionMessageText.replaceAll('{0}', this.multiple ? this.modelValue.length : '1') : this.emptySelectionMessageText;
|
return this.$filled ? this.selectionMessageText.replaceAll('{0}', this.multiple ? this.d_value.length : '1') : this.emptySelectionMessageText;
|
||||||
},
|
},
|
||||||
focusedOptionId() {
|
focusedOptionId() {
|
||||||
return this.focusedOptionIndex !== -1 ? `${this.id}_${this.focusedOptionIndex}` : null;
|
return this.focusedOptionIndex !== -1 ? `${this.id}_${this.focusedOptionIndex}` : null;
|
||||||
|
|
|
@ -114,12 +114,12 @@ const theme = ({ dt }) => `
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const classes = {
|
const classes = {
|
||||||
root: ({ props }) => [
|
root: ({ instance, props }) => [
|
||||||
'p-listbox p-component',
|
'p-listbox p-component',
|
||||||
{
|
{
|
||||||
'p-listbox-striped': props.striped,
|
'p-listbox-striped': props.striped,
|
||||||
'p-disabled': props.disabled,
|
'p-disabled': props.disabled,
|
||||||
'p-invalid': props.invalid
|
'p-invalid': instance.$invalid
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
header: 'p-listbox-header',
|
header: 'p-listbox-header',
|
||||||
|
|
Loading…
Reference in New Issue