259 lines
6.5 KiB
Vue
259 lines
6.5 KiB
Vue
<template>
|
|
<div class="select-multiple-enum user-select-none row w-100 mx-auto">
|
|
<div
|
|
class="col-12 p-0"
|
|
:class="intSpecificItem ? 'col-md-6' : ''"
|
|
>
|
|
<label
|
|
:for="intName"
|
|
class="col-form-label"
|
|
>
|
|
<b>{{ intLabel }} {{ intRequired ? "*" : "" }}</b>
|
|
</label>
|
|
<div class="d-inline-block w-100">
|
|
<VueTagsInputCls
|
|
v-model="intItem"
|
|
:tags="intSelectedItem"
|
|
:autocomplete-items="filteredItems"
|
|
:autocomplete-min-length="0"
|
|
@before-adding-tag="beforeTagSave"
|
|
@tags-changed="changedTags"
|
|
:max-tags="6"
|
|
:placeholder="intPlaceholder"
|
|
/>
|
|
</div>
|
|
<template
|
|
v-for="(sItem, index) in intSelectedItem"
|
|
:key="index"
|
|
>
|
|
<p class="text-danger m-0">
|
|
{{
|
|
parseLaravelErrorMessages.methods.parseValidationInput(
|
|
`${intName}[${String(index)}][name]`,
|
|
intAllErrors
|
|
)
|
|
}}
|
|
</p>
|
|
<input
|
|
:name="`${intName}[${String(index)}]`"
|
|
type="hidden"
|
|
:value="sItem.id"
|
|
>
|
|
</template>
|
|
<small class="form-text text-muted">{{ intHelper }}</small>
|
|
</div>
|
|
<div
|
|
v-if="intSpecificItem && intShowSpecificItem"
|
|
class="col-12 col-md-6 mb-3"
|
|
>
|
|
<label
|
|
for="shop"
|
|
class="col-form-label"
|
|
>
|
|
<b>{{ intSpecificItem.label }}</b>
|
|
</label>
|
|
<p class="text-danger m-0">
|
|
{{ parseLaravelErrorMessages.methods.parseValidationInput(`${intSpecificItem.name}`, intAllErrors) }}
|
|
</p>
|
|
<input
|
|
class="form-control"
|
|
:name="intSpecificItem.name"
|
|
type="text"
|
|
:placeholder="intSpecificItem.placeholder"
|
|
>
|
|
<small class="form-text text-muted">{{ intSpecificItem.helper }}</small>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { computed, onMounted, ref, useAttrs } from "vue";
|
|
import type VueTagsInput from "@sipec/vue3-tags-input";
|
|
import { VueTagsInput as VueTagsInputCls } from "@sipec/vue3-tags-input";
|
|
import slugify from "slugify";
|
|
import parseLaravelErrorMessages from "./../modules/parseLaravelErrorMessages";
|
|
|
|
defineOptions({
|
|
name: "SelectMultipleEnumComponent"
|
|
});
|
|
|
|
// * ATTRIBUTES
|
|
const attrs = useAttrs();
|
|
|
|
// * DATA
|
|
const intName = ref<string>("");
|
|
const intLabel = ref<string>("");
|
|
const intHelper = ref<string>("");
|
|
const intItem = ref<string>("");
|
|
const intSelectedItem = ref<CustomTag[]>([]);
|
|
const intAllItems = ref<CustomTag[]>([]);
|
|
const intPlaceholder = ref<string>("");
|
|
const intItemLimit = ref<number[]>([0, 0]);
|
|
const intAllErrors = ref<Record<string, string[]>>({});
|
|
const intSpecificItem = ref<{
|
|
name: string;
|
|
label: string;
|
|
placeholder: string;
|
|
showId: number;
|
|
helper: string;
|
|
} | null>(null);
|
|
const intShowSpecificItem = ref<boolean>(false);
|
|
const intRequired = ref<boolean>(false);
|
|
|
|
// * LIFECYCLE
|
|
onMounted(() => {
|
|
const json = String(attrs.json ?? "{}"),
|
|
data = JSON.parse(json);
|
|
if (!isUsedWithProps.value) {
|
|
intName.value = data.name;
|
|
intLabel.value = data.label;
|
|
intHelper.value = data.helper;
|
|
intAllItems.value = parseTags(data.itemsList);
|
|
intSelectedItem.value = parseTags(data.itemsSelected);
|
|
intPlaceholder.value = data.placeholder;
|
|
intItemLimit.value = data.itemLimit;
|
|
intAllErrors.value = data.errors;
|
|
intSpecificItem.value = data.showSpecificItem;
|
|
intRequired.value = data.required;
|
|
}
|
|
checkSpecificItem();
|
|
});
|
|
|
|
// * COMPUTED
|
|
const isUsedWithProps = computed<boolean>(() => attrs.json === undefined);
|
|
const filteredItems = computed(() => {
|
|
return intAllItems.value.filter((i) => {
|
|
const label = i.label as string;
|
|
return label.toLowerCase().indexOf(intItem.value.toLowerCase()) !== -1;
|
|
});
|
|
});
|
|
|
|
function parseTags(intSelectedItem: CustomTag[]): CustomTag[] {
|
|
return intSelectedItem.map((intItem: CustomTag) => {
|
|
if (!intItem.value)
|
|
intItem = intAllItems.value
|
|
.filter((intItemEnum) => {
|
|
return intItemEnum.value === intItem;
|
|
})
|
|
.shift() as CustomTag;
|
|
intItem.id = String(intItem.value);
|
|
intItem.text = String(intItem.label);
|
|
return intItem;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Add item
|
|
* @param obj
|
|
*/
|
|
function beforeTagSave(obj: VueTagsInput.IAddArgs): void {
|
|
if (intSelectedItem.value.length < intItemLimit.value[1]) {
|
|
const customTag = tagExists(intAllItems.value, obj.tag);
|
|
if (customTag) {
|
|
obj.tag = customTag as unknown as VueTagsInput.ITag;
|
|
intSelectedItem.value.push(customTag);
|
|
intItem.value = "";
|
|
checkSpecificItem();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if the specific item must be shown.
|
|
* @param newItem
|
|
*/
|
|
function checkSpecificItem(): void {
|
|
if (intSpecificItem.value) {
|
|
intShowSpecificItem.value = intSelectedItem.value.some((item) => {
|
|
return item.value == String(intSpecificItem.value?.showId);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete item.
|
|
* @param newItem
|
|
*/
|
|
function changedTags(newItem: CustomTag[]): void {
|
|
intSelectedItem.value = newItem as CustomTag[];
|
|
checkSpecificItem();
|
|
}
|
|
|
|
/**
|
|
* Verify if the tag exist.
|
|
* @param newItem
|
|
*/
|
|
function tagExists(
|
|
items: CustomTag[],
|
|
tagToCheck: VueTagsInput.ITag
|
|
): CustomTag | null {
|
|
let customTag: CustomTag | null = null;
|
|
items.filter((intItem: CustomTag) => {
|
|
if (
|
|
intItem.value === (tagToCheck as unknown as CustomTag).value ||
|
|
intItem.label === slugify(tagToCheck.text)
|
|
) {
|
|
customTag = intItem;
|
|
}
|
|
});
|
|
return customTag;
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.select-multiple-enum {
|
|
max-width: 100% !important;
|
|
|
|
.vue-tags-input {
|
|
max-width: 100% !important;
|
|
}
|
|
|
|
.ti- {
|
|
&autocomplete {
|
|
max-height: 10rem !important;
|
|
border-radius: 0.375rem;
|
|
box-shadow: 0 0 4px var(--bs-gray-400);
|
|
overflow-y: auto !important;
|
|
|
|
ul {
|
|
padding: 0.25rem 0 !important;
|
|
}
|
|
}
|
|
|
|
&input {
|
|
padding: 0.375rem !important;
|
|
border-radius: 0.375rem;
|
|
}
|
|
|
|
&tags {
|
|
line-height: inherit !important;
|
|
}
|
|
|
|
&tag,
|
|
&new-tag-input-wrapper {
|
|
padding: 0.1rem !important;
|
|
margin: 0.1rem !important;
|
|
}
|
|
|
|
&new-tag-input-wrapper {
|
|
font-size: 1em !important;
|
|
|
|
input {
|
|
min-width: 17rem !important;
|
|
}
|
|
}
|
|
|
|
&tag {
|
|
padding: 0.1rem 0.3rem !important;
|
|
background-color: #0d6efd !important;
|
|
border-radius: 0.375rem !important;
|
|
}
|
|
|
|
&selected-item {
|
|
background-color: var(--bs-gray-300) !important;
|
|
color: var(--bs-gray-900) !important;
|
|
}
|
|
}
|
|
}
|
|
</style>
|