-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Question: How to provide dynamic data to combobox? #52
Comments
Great question! Off the top of my head I can't think of anywhere I've used dynamic data like this ... well, I have data loaded, but it's effectively static to the control. You're really talking about using it for a possibly unbounded set of data (or more than you'd want to load and have in memory upfront). I'll have a think about the best way to do it. I'd imagine having some function you can pass to the control factory to fetch the data is what's needed. |
That seems to be the approach used in simple-svelte-autocomplete which seems to work fairly well. Although it's overloaded with more functionality than I need. Also, I wouldn't include "unbounded sets" of data in the requirement since pulling in the top 10-20 items is all I'm interested in. |
Yeah, I meant a subset from a potentially larger set (the unbounded). I'd probably include some form of virtualization for the list too, as you may have many more entries in a result than you want to load / render unless and until someone scrolls. |
The solution I'm using basically just hijacks the input change option in a search input and feeds the subsequent results in to the combobox, while providing my own logic for the <script lang="ts">
const combobox = createCombobox();
let searchPromise: Promise<void>;
let query: string;
let searchResults: any[];
async function search() {
try {
const result = await fetch(
`${import.meta.env.VITE_API_BASE_URL}/api/v1/search?query=${query}`
);
searchResults = await result.json();
}
}
</script>
<input
type="search"
name="search"
use:combobox.input
on:input={() => {
searchPromise = search();
}}
on:select={onSelect}
on:keydown={scrollToActiveItem}
bind:value={query}
/>
{#if Boolean(query)}
<!-- optionally await searchPromise -->
<ul
use:combobox.items
>
{#each searchResults as result}
{@const active = $combobox.active === result}
<li
<!-- optional custom active classes -->
use:combobox.item={{ value: result }}
>
{result.toString()}
</li>
{/each}
</ul>
{/if} |
Try this:
const combobox = createCombobox()
const filter = derived(combobox, $combobox => $combobox.filter)
let filtered: any[] = []
$: fetchData($filter)
async function fetchData(filter: string) {
if (browser) {
const q = filter.toLowerCase().replace(/\s+/g, '')
const resp = await fetch('/api/data?q=' + q)
const data = await resp.json()
filtered = data
}
} 3: Use the {#each filtered as value}
...
{/each} |
Hello and thanks for taking on HeadlessUI for Svelte! I'm just starting to play around with it and am having some trouble understanding the right way to provide dynamic data to combobox results.
I'd like to use the combobox as an autocomplete for a dynamic form. As the user types, I'll send out an API call to find all of the matching entries and fill in the results in the dropdown as they stream in.
I've tried updating the combobox state directly, e.g.
combobox.set({items: itemsFromServer})
whenever the API call finishes. However, I'm not able to use the combobox's filter without ending up in an infinite loop.What's the right way to go about this?
Thanks!
e.q.
The text was updated successfully, but these errors were encountered: