sycamore-rs / sycamore

A library for creating reactive web apps in Rust and WebAssembly
https://sycamore-rs.netlify.app
MIT License
2.79k stars 148 forks source link

Support binding to a radio input value #658

Open vi opened 7 months ago

vi commented 7 months ago

Supposing I have an enum to be chosen by user using radio boxes. What is the best way to do with with Sycamore?

enum SomeChoice {
   Qqq,
   Www,
   Eee,
}

let thesignal = create_signal(SomeChoice::Qqq);

view! {
    label { "Qqq" input(type="radio" , name="somechoice", value="qqq", bind:checked=???)  }
    label { "Www" input(type="radio",  name="somechoice", value="www")  } 
    label { "Eee" input(type="radio",  name="somechoice", value="eee") }
}
vi commented 7 months ago

Workaround I use now:

        let somechoice_qqq = create_signal(false);
        let somechoice_www = create_signal(false);
        let somechoice_eee = create_signal(false);

        let the_choice = create_signal(SomeChoice::Qqq);

        create_effect(move || { if somechoice_qqq.get() { the_choice.set(SomeChoice::Qqq)} });
        create_effect(move || { if somechoice_www.get() { the_choice.set(SomeChoice::Www)} });
        create_effect(move || { if somechoice_eee.get() { the_choice.set(SomeChoice::Eee)} });

and using usual bind:checked=somechoice_qqq binders. It seems to work, but only in one direction.

Also for some reason bool signals for individual variants (like somechoice_qqq) only get set to true, never back to false.

lukechu10 commented 7 months ago

Also for some reason bool signals for individual variants (like somechoice_qqq) only get set to true, never back to

This sounds like a bug. Will need to investigate this. This might be caused by the event that we listen to for the checked being different when the input is a radio, although I'll have to do a bit more research to be sure.

Unfortunately we don't really have a good way to do this yet. What we want eventually is probably something like Svelte's bind:group. (In fact, the current bind: syntax is inspired by Svelte.)

For now, I would suggest that a more idiomatic and simpler workaround would be to use on:click event handlers to directly set the thesignal to the appropriate value. So something like:

view! {
    label { "Qqq" input(type="radio", name="somechoice", value="qqq", on:click=move |_| thesignal.set(SomeChoice::Qqq)) }
    label { "Www" input(type="radio", name="somechoice", value="www", on:click=move |_| thesignal.set(SomeChoice::Www)) } 
    label { "Eee" input(type="radio", name="somechoice", value="eee", on:click=move |_| thesignal.set(SomeChoice::Eee)) }
}