Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Svelte: How to stop the {#await} block from getting refreshed every time the bound attribute is changed?

I'm trying to initialize a <select/> input with the data obtained from a Promise based function. After the input initializes the options (each option gets the value and label from the resolved data), an attribute is bound to the <select/>.

But every time I change the option (with the attribute binding), everything inside the {#await} block gets reloaded (seems like its resolving the same Promise and resetting the options).

This doesn't happen when I remove the binding.

I have tried the following:

  • Tried binding an attribute to the select.

    `<select bind:value={selected_device}>...`
    
  • Tried binding an event that gets the selected option from the list.

    `<select on:change={set_selected_device}>...`
    
  • Tried making another button to get the selected option.

    <select>...</select>
    <button on:click={set_selected_device}>Set</button>`
    

This is the snippet of the current state:

The Await Block:

<div class="device-select container">
  {#await VoiceStreamingService.get_microhpones()}

  {:then devices}
    <select id="device-options">
      <option selected disabled>Select an Option...</option>
      {#each devices as device (device.deviceId)}
        <option value={device.deviceId}>{device.label}</option>
      {/each}
    </select>
  {:catch}

  {/await}
  <button on:click={set_selected_device}>Connect To</button>
</div>

The set_selected_device function:

function set_selected_device() {
    let d = document.getElementById("device-options");
    selected_device = d.options[d.selectedIndex].value;
    console.log(selected_device);
  }

Am I missing something important, or is it a bug?

like image 962
Ashik Unni Avatar asked Oct 20 '25 23:10

Ashik Unni


2 Answers

I'm afraid it's a bug: https://github.com/sveltejs/svelte/issues/2355

A workaround is to create a variable in your script...

let promise = VoiceStreamingService.get_microhpones();

and await that instead of the expression.

like image 177
Rich Harris Avatar answered Oct 23 '25 15:10

Rich Harris


I tried to resolve the promise once component was mounted and then pushed the options to the select object.

Sharing the code below:

onMount(() => {
  (async () => {
    let select = document.getElementById("device-options");
    try {
      (await VoiceStreamingService.get_microhpones()).forEach(device => {
        let option = document.createElement("option");
        option.value = device.deviceId;
        option.innerHTML = device.label;
        select.appendChild(option);
      });
    } catch (e) {
      console.log(e);
    }
  })();
});
like image 39
Ashik Unni Avatar answered Oct 23 '25 14:10

Ashik Unni