mirror of https://github.com/halo-dev/halo
[release-2.19] fix: formkit select component not emitting event or updating selection on value change (#6610)
This is an automated cherry-pick of #6602 /assign LIlGG ```release-note 解决 Formkit Select 组件在值变更时不会发出事件及修改选项值的问题。 ```pull/6613/head
parent
f538f2f6d3
commit
dfa10c06a4
|
@ -2,18 +2,18 @@
|
|||
import { IconArrowDownLine, IconCloseCircle } from "@halo-dev/components";
|
||||
import {
|
||||
computed,
|
||||
defineEmits,
|
||||
nextTick,
|
||||
onMounted,
|
||||
ref,
|
||||
defineEmits,
|
||||
type PropType,
|
||||
onUnmounted,
|
||||
ref,
|
||||
type PropType,
|
||||
} from "vue";
|
||||
|
||||
import SelectSelector from "./SelectSelector.vue";
|
||||
import { Dropdown } from "floating-vue";
|
||||
import MultipleSelectSelector from "./MultipleSelectSelector.vue";
|
||||
import SelectDropdownContainer from "./SelectDropdownContainer.vue";
|
||||
import { Dropdown } from "floating-vue";
|
||||
import SelectSelector from "./SelectSelector.vue";
|
||||
|
||||
const props = defineProps({
|
||||
multiple: {
|
||||
|
@ -95,7 +95,7 @@ const inputRef = ref<HTMLInputElement | null>();
|
|||
const searchKeyword = ref<string>("");
|
||||
const isDropdownVisible = ref<boolean>(false);
|
||||
const selectedOptions = computed({
|
||||
get: () => props.selected,
|
||||
get: () => [...props.selected],
|
||||
set: (value) => {
|
||||
emit("update", value);
|
||||
},
|
||||
|
|
|
@ -45,7 +45,7 @@ export interface SelectProps {
|
|||
remoteOptimize?: boolean;
|
||||
|
||||
/**
|
||||
* Allows the creation of new options, only available in local mode.
|
||||
* Allows the creation of new options, only available in local mode. Default is false.
|
||||
*/
|
||||
allowCreate?: boolean;
|
||||
|
||||
|
@ -209,7 +209,7 @@ const initSelectProps = () => {
|
|||
selectProps.maxCount = nodeProps.maxCount ?? NaN;
|
||||
selectProps.placeholder = nodeProps.placeholder ?? "";
|
||||
selectProps.action = nodeProps.action ?? "";
|
||||
selectProps.remoteOptimize = nodeProps.remoteOptimize ?? true;
|
||||
selectProps.remoteOptimize = !isFalse(nodeProps.remoteOptimize, true);
|
||||
selectProps.requestOption = {
|
||||
...{
|
||||
method: "GET",
|
||||
|
@ -225,12 +225,12 @@ const initSelectProps = () => {
|
|||
...(nodeProps.requestOption ?? {}),
|
||||
};
|
||||
selectProps.multiple = !isFalse(nodeProps.multiple);
|
||||
selectProps.sortable = !isFalse(nodeProps.sortable);
|
||||
selectProps.sortable = !isFalse(nodeProps.sortable, true);
|
||||
selectProps.remote = !isFalse(nodeProps.remote);
|
||||
selectProps.allowCreate = !isFalse(nodeProps.allowCreate);
|
||||
selectProps.clearable = !isFalse(nodeProps.clearable);
|
||||
selectProps.searchable = !isFalse(nodeProps.searchable);
|
||||
selectProps.autoSelect = !isFalse(nodeProps.autoSelect) || true;
|
||||
selectProps.autoSelect = !isFalse(nodeProps.autoSelect, true);
|
||||
if (selectProps.remote) {
|
||||
if (!nodeProps.remoteOption) {
|
||||
throw new Error("remoteOption is required when remote is true.");
|
||||
|
@ -543,14 +543,25 @@ const getAutoSelectedOption = ():
|
|||
});
|
||||
};
|
||||
|
||||
const stopSelectedWatch = watch(
|
||||
() => [options.value, props.context.value],
|
||||
async () => {
|
||||
if (options.value) {
|
||||
watch(
|
||||
() => props.context.value,
|
||||
async (newValue) => {
|
||||
const selectedValues = selectOptions.value?.map((item) => item.value) || [];
|
||||
if (selectedValues.length > 0 && selectedValues.includes(newValue)) {
|
||||
return;
|
||||
}
|
||||
const selectedOption = await fetchSelectedOptions();
|
||||
selectOptions.value = selectedOption;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => options.value,
|
||||
async (newOptions) => {
|
||||
if (newOptions && newOptions.length > 0) {
|
||||
const selectedOption = await fetchSelectedOptions();
|
||||
if (selectedOption) {
|
||||
selectOptions.value = selectedOption;
|
||||
return;
|
||||
}
|
||||
const isAutoSelect =
|
||||
selectProps.autoSelect &&
|
||||
|
@ -562,12 +573,12 @@ const stopSelectedWatch = watch(
|
|||
// Automatically select the first option when the selected value is empty.
|
||||
const autoSelectedOption = getAutoSelectedOption();
|
||||
if (autoSelectedOption) {
|
||||
selectOptions.value = [autoSelectedOption];
|
||||
handleUpdate(selectOptions.value);
|
||||
handleUpdate([autoSelectedOption]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
// When attr options are processed asynchronously, it is necessary to monitor
|
||||
|
@ -581,14 +592,27 @@ watch(
|
|||
}
|
||||
);
|
||||
|
||||
const handleSelectedUpdate = (
|
||||
value: Array<{ label: string; value: string }>
|
||||
) => {
|
||||
stopSelectedWatch();
|
||||
handleUpdate(value);
|
||||
const handleUpdate = async (value: Array<{ label: string; value: string }>) => {
|
||||
const oldSelectValue = selectOptions.value;
|
||||
if (
|
||||
oldSelectValue &&
|
||||
value.length === oldSelectValue.length &&
|
||||
value.every((item, index) => item.value === oldSelectValue[index].value)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const newValue = value.map((item) => {
|
||||
return {
|
||||
label: item.label,
|
||||
value: item.value,
|
||||
};
|
||||
});
|
||||
handleSetNodeValue(newValue);
|
||||
await props.context.node.settled;
|
||||
props.context.attrs.onChange?.(newValue);
|
||||
};
|
||||
|
||||
const handleUpdate = (value: Array<{ label: string; value: string }>) => {
|
||||
const handleSetNodeValue = (value: Array<{ label: string; value: string }>) => {
|
||||
const values = value.map((item) => item.value);
|
||||
selectOptions.value = value;
|
||||
if (selectProps.multiple) {
|
||||
|
@ -725,7 +749,7 @@ const handleNextPage = async () => {
|
|||
:clearable="selectProps.clearable"
|
||||
:searchable="selectProps.searchable"
|
||||
:auto-select="selectProps.autoSelect"
|
||||
@update="handleSelectedUpdate"
|
||||
@update="handleUpdate"
|
||||
@search="handleSearch"
|
||||
@load-more="handleNextPage"
|
||||
/>
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
export const isFalse = (value: string | boolean | undefined | null) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const isFalse = (value: any, onlyBoolean = false) => {
|
||||
if (onlyBoolean) {
|
||||
return [false, "false"].includes(value);
|
||||
}
|
||||
return [undefined, null, "false", false].includes(value);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue