Commit 2b29c666 authored by Ahmed Awan's avatar Ahmed Awan
Browse files

add explicit track by id functionality to `FormSelect`

parent 165cff93
Loading
Loading
Loading
Loading
+33 −5
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ type ValueWithTags = SelectValue & { tags: string[] };
interface SelectOption {
    label: string;
    value: SelectValue;
    id?: string;
}

const props = defineProps({
@@ -64,22 +65,29 @@ const filteredOptions = useFilterObjectArray(() => props.options, filter, ["labe
const optionReorderThreshold = 8;

const reorderedOptions = computed(() => {
    let result;
    if (!props.multiple || filteredOptions.value.length <= optionReorderThreshold) {
        return filteredOptions.value;
        result = filteredOptions.value;
    } else {
        const selectedOptions: SelectOption[] = [];
        const unselectedOptions: SelectOption[] = [];

        filteredOptions.value.forEach((option) => {
            if (selectedValues.value.includes(option.value)) {
            if (isSelected(option.value)) {
                selectedOptions.push(option);
            } else {
                unselectedOptions.push(option);
            }
        });

        return [...unselectedOptions, ...selectedOptions];
        result = [...unselectedOptions, ...selectedOptions];
    }
    return result.map((option) => {
        return {
            ...option,
            id: trackBy.value === "id" && isValueWithId(option.value) ? option.value.id : undefined,
        };
    });
});

/**
@@ -114,15 +122,25 @@ const selectedLabel: ComputedRef<string> = computed(() => {
 */
const selectedValues = computed(() => (Array.isArray(props.value) ? props.value : [props.value]));

/**
 * Tracks selected ids in case of objects with string ids
 */
const selectedIds = computed(() => {
    return selectedValues.value.map((v) => (isValueWithId(v) ? v.id : undefined)).filter((v) => v !== undefined);
});

/**
 * Whether current value(s) will be tracked by id or value
 */
const trackBy = computed(() => {
    return selectedIds.value.length > 0 ? "id" : "value";
});

/**
 * Tracks current value and emits changes
 */
const currentValue = computed({
    get: () => props.options.filter((option: SelectOption) => selectedValues.value.includes(option.value)),
    get: () => props.options.filter((option: SelectOption) => isSelected(option.value)).map(getSelectOption),
    set: (val: Array<SelectOption> | SelectOption): void => {
        if (Array.isArray(val)) {
            if (val.length > 0) {
@@ -146,6 +164,16 @@ function setInitialValue(): void {
    }
}

function getSelectOption(option: SelectOption): SelectOption {
    if (isValueWithId(option.value)) {
        return {
            ...option,
            id: option.value.id,
        };
    }
    return option;
}

/**
 * Watches changes in select options and adjusts initial value if necessary
 */
@@ -200,7 +228,7 @@ function isSelected(item: SelectValue): boolean {
            :placeholder="placeholder"
            :selected-label="selectedLabel"
            :select-label="null"
            track-by="value"
            :track-by="trackBy"
            :internal-search="false"
            @search-change="onSearchChange"
            @open="onOpen"