120 lines
2.6 KiB
Vue
120 lines
2.6 KiB
Vue
<script setup>
|
|
import {ref, watch} from "vue";
|
|
|
|
const props = defineProps({
|
|
modelValue: {
|
|
type: [Object, Array]
|
|
},
|
|
rules: {
|
|
type: Array,
|
|
required: false,
|
|
default: () => []
|
|
},
|
|
enableNewValues: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: true,
|
|
},
|
|
options: {
|
|
type: Array,
|
|
required: true,
|
|
},
|
|
optionLabel: {
|
|
type: String,
|
|
required: false,
|
|
default: "name"
|
|
},
|
|
optionValue: {
|
|
type: String,
|
|
required: false,
|
|
default: "id"
|
|
}
|
|
})
|
|
|
|
const model = ref({});
|
|
watch(() => props.modelValue, (newVal) => {
|
|
model.value = newVal;
|
|
}, {immediate: true});
|
|
|
|
const emit = defineEmits(['update:modelValue', 'clear']);
|
|
watch(model, (val) => {
|
|
if (!val) return;
|
|
|
|
let value = val;
|
|
if (typeof val === 'string') value = {name: val};
|
|
if (value['__typename']) {
|
|
delete value['__typename'];
|
|
}
|
|
emit("update:modelValue", value);
|
|
})
|
|
|
|
const clearValue = () => {
|
|
model.value = {};
|
|
emit("clear");
|
|
}
|
|
|
|
const inputValue = ref("");
|
|
const inputValueChanged = (value) => {
|
|
if (model.value?.name && value !== '') {
|
|
// reset model
|
|
delete model.value.id;
|
|
model.value.name = '';
|
|
}
|
|
inputValue.value = value;
|
|
}
|
|
|
|
const handleOnBlur = () => {
|
|
if (inputValue.value !== '') {
|
|
model.value = inputValue.value;
|
|
inputValue.value = "";
|
|
}
|
|
}
|
|
|
|
let availableOptions = ref([]);
|
|
const filterFn = (val, update, abort) => {
|
|
update(() => {
|
|
if (!val || val === "") {
|
|
availableOptions.value = props.options;
|
|
} else {
|
|
const needle = val.toLowerCase();
|
|
availableOptions.value = props.options.filter(v => {
|
|
return v.name.toLowerCase().indexOf(needle) > -1;
|
|
});
|
|
}
|
|
|
|
availableOptions.value = availableOptions.value.map(i => ({id: i.id, name: i.name}))
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<q-select
|
|
v-model="model"
|
|
use-input
|
|
input-debounce="100"
|
|
:display-value="`${model ? model[optionLabel] : ''}`"
|
|
:rules="rules"
|
|
@filter="filterFn"
|
|
@input-value="inputValueChanged"
|
|
@blur="handleOnBlur"
|
|
@clear="clearValue"
|
|
:options="availableOptions"
|
|
:option-label="optionLabel"
|
|
:option-value="optionValue"
|
|
:new-value-mode="enableNewValues ? 'add' : 'toggle'"
|
|
clear-icon="clear"
|
|
:v-bind="$attrs"
|
|
>
|
|
<template v-slot:no-option v-if="enableNewValues">
|
|
<q-item v-if="inputValue">
|
|
<q-item-section avatar>
|
|
<q-avatar text-color="green" size="32px" icon="add"/>
|
|
</q-item-section>
|
|
<q-item-section class="text-grey">
|
|
<span>Vytvořit novou hodnotu <q-chip>{{ inputValue }}</q-chip></span>
|
|
</q-item-section>
|
|
</q-item>
|
|
</template>
|
|
</q-select>
|
|
</template>
|