Closed Cluster2a closed 1 year ago
I was playing with the code and made some minor changes (there might be a better approach).
export let loadOptionsOnOpen = false;
function setupFilterText() {
if ((!loadOptions || loadOptionsOnOpen) && filterText.length === 0) return;
if (loadOptions) {
debounce(async function () {
loading = true;
let res = await getItems({
dispatch,
loadOptions,
convertStringItemsToObjects,
filterText,
});
if (res) {
loading = res.loading;
listOpen = listOpen ? res.listOpen : filterText.length > 0 ? true : false;
focused = listOpen && res.focused;
items = groupBy ? filterGroupedItems(res.filteredItems) : res.filteredItems;
} else {
loading = false;
focused = true;
listOpen = true;
}
}, debounceWait);
} else {
listOpen = true;
if (multiple) {
activeValue = undefined;
}
}
}
async function handleClick() {
if (disabled) return;
if(loadOptionsOnOpen && !items.length) {
loading = true;
let res = await getItems({
dispatch,
loadOptions,
convertStringItemsToObjects,
filterText,
});
if (res) {
loading = res.loading;
items = groupBy ? filterGroupedItems(res.filteredItems) : res.filteredItems;
listOpen = !listOpen;
} else {
loading = false;
}
} else {
listOpen = !listOpen;
}
}
The ability to load the data just on open makes sense since some fields might not be used that often. Fetching the data should not happen on rendering in any case.
Creating your own implementation with the events is dirty since you have to take care of the rendering empty-slot, the loading prop, and so on. There should be a more user-friendly way of doing this.
You could bind:listOpen
and use that as a flag in your loadOptions
method.
Basic loadOptions
example: https://svelte-select-examples.vercel.app/examples/props/loadOptions
@rob-balfre, then I could check in the loadOptions
if the listOpen === true
and skip the API call, if it's not open.
But if I open the select field, the loadOptions
is not executed again, so the data will never be fetched. Or am I getting something wrong?
@rob-balfre, I tried something like this:
<script lang="ts">
import Select from 'svelte-select';
import LL from '$i18n/i18n-svelte';
import { ApiProblemKind } from '$lib/services/api/api-problem';
import { ProjectApi } from '$lib/services/api/project-api';
import type { ProjectSelectionListResult } from '$lib/services/api/types/project-api.types';
import ProjectItem from '$lib/Components/shared/SvelteSelect/Projects/Item.svelte';
import IconClear from '$lib/Components/shared/SvelteSelect/Icons/Clear.svelte';
export let value = [];
export let justValue = '';
export let id: string;
let selectOptions = [];
let listOpen = false;
let loadingItems = false;
const floatingConfig = {
strategy: 'fixed'
};
$: {
if (listOpen && selectOptions.length === 0) {
loadOptions();
}
}
const loadOptions = async () => {
loadingItems = true;
const projectAPI = new ProjectApi();
try {
const result: ProjectSelectionListResult = await projectAPI.selections();
if (result.kind === ApiProblemKind.ok) {
selectOptions = result.data.projects.map((project) => {
return {
value: project.id,
label: project.name,
name: project.name,
color: project.color,
number: project.number,
status: project.status
};
});
}
} catch (error) {
console.error(error);
} finally {
loadingItems = false;
}
};
</script>
<Select
bind:id
items={selectOptions}
bind:value
bind:justValue
multiple={true}
placeholder="Select project"
bind:listOpen
{floatingConfig}
loading={loadingItems}
--list-position="fixed"
>
<div slot="item" let:item>
<ProjectItem {item} />
</div>
<div slot="selection" let:selection>
<ProjectItem item={selection} />
</div>
<div slot="clear-icon">
<IconClear />
</div>
<div slot="empty" class="empty">
{$LL.components.booking.modal.editNewModal.tabs.mainData.projectNoOptions()}
</div>
</Select>
This works as desired, but the result looks like this:
Since the items are loaded after the select is opened, it seems like the width of the items is not adjusted to the width of the select. The second time I open the select, everything looks fine.
Basic example of loadOptions
and listOpen
here:
https://svelte.dev/repl/6f92e1b8b646438683d02766f7c20049?version=3.57.0
Can't really help with big detailed examples like that, too much to debug for little old me.
@rob-balfre, I made a fork of your repo with a pre selection: https://svelte.dev/repl/cf6044a8389d4a25b42062f9aa9a627c?version=3.57.0
Sometimes, we already have the data, so fetching it is unnecessary. Is there a way to delete the selected item? The only way to do so is to open the selection once - then the clear component is rendered.
Hey,
I want to load the options via API only if the user opens the select field.
loadOptions
seems to be called on mount.I tried with on:focus, but the UI got a bit messy.
Is there a recommended way to do this? It would be awesome if the loadOptions would be called if listOpen = true, to avoid over-fetching data. Or if there would be a loadOptionsOnOpen-Parameter.
I really appreciate any help you can provide.