seitime-frappe/frappe/public/js/form_builder/components/controls/SelectControl.vue

141 lines
3.1 KiB
Vue

<script setup>
import { useSlots, onMounted, ref, computed, watch } from "vue";
const props = defineProps(["df", "read_only", "modelValue", "no_label"]);
let emit = defineEmits(["update:modelValue"]);
let slots = useSlots();
let select = ref(null);
let update_control = ref(true);
function get_options() {
let options = props.df.options;
if (typeof options == "string") {
options = options.split("\n") || "";
options = options.map((opt) => {
return { label: __(opt), value: opt };
});
}
if (options?.length && typeof options[0] == "string") {
options = options.map((opt) => {
return { label: __(opt), value: opt };
});
}
if (props.df.fieldname == "fieldtype") {
if (!in_list(frappe.model.layout_fields, props.modelValue)) {
options =
options &&
options.filter((opt) => !in_list(frappe.model.layout_fields, opt.value));
} else {
options = [{ label: __(props.modelValue), value: props.modelValue }];
}
}
if (props.df.sort_options) {
options.sort((a, b) => a.label.localeCompare(b.label));
}
return options;
}
let select_control = computed(() => {
if (!select.value) return;
select.value.innerHTML = "";
return frappe.ui.form.make_control({
parent: select.value,
df: {
...props.df,
fieldtype: "Select",
hidden: 0,
options: get_options(),
read_only: Boolean(slots.label) || props.read_only,
change: () => {
if (update_control.value) {
content.value = select_control.value.get_value();
}
update_control.value = true;
},
},
value: content.value,
render_input: true,
only_input: Boolean(slots.label) || props.no_label,
});
});
let content = computed({
get: () => props.modelValue ?? props.df.default,
set: (value) => emit("update:modelValue", value),
});
// Get the display label for the current selected value
let display_value = computed(() => {
const current_value = content.value;
if (!current_value) return "";
const options = get_options();
const selected_option = options?.find((opt) => opt.value === current_value);
return selected_option ? selected_option.label : current_value;
});
onMounted(() => {
if (select.value) select_control.value;
});
watch(
() => content.value,
(value) => {
update_control.value = false;
select_control.value?.set_value(value);
}
);
watch(
() => props.df.options,
() => {
select_control.value;
}
);
</script>
<template>
<div v-if="slots.label" class="control frappe-control" :class="{ editable: slots.label }">
<!-- label -->
<div class="field-controls">
<slot name="label" />
<slot name="actions" />
</div>
<!-- select input -->
<div class="select-input">
<input class="form-control" readonly :value="display_value" />
<div class="select-icon" v-html="frappe.utils.icon('select', 'sm')"></div>
</div>
<!-- description -->
<div v-if="df.description" class="mt-2 description" v-html="df.description"></div>
</div>
<div v-else class="control" ref="select"></div>
</template>
<style lang="scss" scoped>
.editable {
.select-icon {
top: 3px !important;
}
}
.select-input {
position: relative;
.select-icon {
position: absolute;
pointer-events: none;
top: 5px;
right: 10px;
}
}
</style>