Skip to content
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

select value is not reflected if the list of options are loaded at a later time #2241

Open
westbrma opened this issue Jul 30, 2024 · 6 comments
Labels
enhancement New feature or request

Comments

@westbrma
Copy link

Describe the bug

I am loading a list of select options from an API so the options get populated a bit after the element is rendered. The value of the select is already set but is not reflected after the list is loaded.

Your Example Website or App

https://playground.solidjs.com/anonymous/afff844c-d8cb-40ab-b368-7b0fe268ab6d

Steps to Reproduce the Bug or Issue

  1. create a set its value use to populate its options from an array load the array of options using a timeout so that is populated after the render Expected behavior I expect the value of the select to be reflect the correct option regardless of when that option is rendered Screenshots or Videos No response Platform Browser: [Chrome] Additional context No response
@westbrma westbrma changed the title select value is not reflected if the list of options are changed or loaded at a later time select value is not reflected if the list of options are loaded at a later time Jul 30, 2024
@maciek50322
Copy link

You can make it work with either:

  1. Update state.color to different value, so that the <select> gets notified of update, like so:
const state = createMutable({
  color: undefined, //undefined, so later it we can assign different value
  options: [];
})
setTimeout(() => {
  state.options.push(Color.Red)
  state.options.push(Color.Blue)
  state.color = Color.Blue
}, 1000)
  1. A bit more implicit, but subscribe to state.options.length change in <select>'s value:
return <select value={state.options.length && state.color} ... >
  1. Or similarly you could use index instead of value of your color (but this requires new object for state.options, as we don't subscribe to it's length):
const state = createMutable({
  colorIndex: 1,
  options: [];
})
setTimeout(() => {
  state.options = [Color.Red, Color.Blue]
}, 1000)
return <select value={state.options[state.colorIndex]} ... >
  1. Take bit different approach and instead of using value on <select>, use selected on <option> with use of createSelector (or state.color === o):
    https://playground.solidjs.com/anonymous/85464d7a-2dfa-479d-93fb-8e93f04b745d

But I wonder if it's possible to make it work for your code

@westbrma
Copy link
Author

@maciek50322 thank you for the detailed workarounds. Since this works automatically with Vue and React it would be nice to have one less gotcha for devs making the transition to Solid.

@ryansolid
Copy link
Member

ryansolid commented Jul 30, 2024

We don't re-render like React or Vue so there has to be some level of different expectations here. My usual go to is how VanillaJS works. If you have a select that has a value and options are added later does it work?

https://playground.solidjs.com/anonymous/70df1286-3b10-48c6-9b5a-c7c2ae93d018
Apparently not.. value has to always be reset after options change.

There is a big difference to me between things that are conceptually synchronous not working as that makes no sense(order shouldn't be your concern), and things that happen asynchronously.

I do think select is an awkward design. The fact it forces you to set its value again is tedious. I'd be willing to look at solving this but it starts with being able to come up with a vanilla approach. The problem is we will not be re-rendering, and reactively these things can be changed independently as they can exist in different files even with no connection. They can be wrapped in components even or rendered using Dynamic.

@maciek50322
Copy link

https://playground.solidjs.com/anonymous/70df1286-3b10-48c6-9b5a-c7c2ae93d018 Apparently not.. value has to always be reset after options change.

Interesting thing here is that it won't change even if you do

select.value = Color.Red

At the end, after adding options. I assumed solid does some custom magic for select value prop (similar to svg props),
value isn't html's attribute for select, as mentioned in thread here
https://stackoverflow.com/a/44798498

@ryansolid
Copy link
Member

We don't use attributes for value and always we use the property.. That works. Also If you move the select.value into the timeout then it works. But we have no way of know we need to do that. The problem is the value must be set after the option is present otherwise it won't show it even if an option of the same name is added later. That is weird DOM behavior but also has us in a weird place unless we want to maybe like listen to DOM events.. like create mutation observer maybe? All we can do is declaratively make sure it runs last. Which we can do. But that doesn't help if someone tries to add options after the fact without setting the value as well.

@ryansolid ryansolid added the enhancement New feature or request label Sep 23, 2024
@titoBouzout
Copy link
Contributor

Something forgotten this days, is that you can just tell which value is selected when creating the options.
https://playground.solidjs.com/anonymous/425eb7c6-1a16-49ed-8eaf-f49cb207dd86
The only thing I have changed, is to add a selected attribute to the option as in
<option value={o} selected={state.color === o}>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants