headlessui icon indicating copy to clipboard operation
headlessui copied to clipboard

Vue ComboboxOption `selected` Not Updated

Open aronduby opened this issue 2 years ago • 1 comments

What package within Headless UI are you using? @headlessui/vue

What version of that package are you using? v1.6.5

What browser are you using? Chrome

Reproduction URL https://codesandbox.io/s/headless-combobox-cih5y9

Describe your issue

The selected slot property isn't being updated when the model is updated outside of the component. In the example there's an additional list with buttons to remove items by index. It properly removes them from the value as shown in pre output, but the selected attribute doesn't update and items incorrectly stay marked as selected.

image

aronduby avatar Jun 22 '22 16:06 aronduby

The bug only occurs when the static option is true in ComboboxOptions.

Solution You can fix it adding :key="selectedPeople.length" in ComboboxOptions. That way you force the component to re-render when the amount of elements changes.

Reproduction URL: https://codesandbox.io/s/headless-combobox-forked-6dp0y6?file=/src/components/ComboBox.vue:125-140

EvertonWingert avatar Jun 23 '22 14:06 EvertonWingert

Hey! Thank you for your bug report! Much appreciated! 🙏

This is interesting, I think that somehow this might be a Vue bug where the mutation using splice doesn't give you the wanted result. The workaround provided by @EvertonWingert seems to work, and looking at your original CodeSandbox it seems like you already implemented that.

The reason why I think it is a Vue bug is because if you replace the splice with this:

- selectedPeople.value.splice(idx, 1);
+ selectedPeople.value = selectedPeople.value.filter((_, i) => i !== idx);

It totally works, which makes me think that this is a bug in the reactivity / watching / proxy implementation within Vue.

I think it might be looking for "assigments" (via Proxy setters), because if you do this:

  selectedPeople.value.splice(idx, 1);
+ selectedPeople.value = selectedPeople.value.slice();

It also totally works!

RobinMalfait avatar Aug 30 '22 10:08 RobinMalfait