huh icon indicating copy to clipboard operation
huh copied to clipboard

Dynamic Inputs

Open maaslalani opened this issue 9 months ago • 2 comments

Dynamic Forms

Country / State form with dynamic inputs running.

huh? forms can now react to changes in other parts of the form. Replace properties such as Options, Title, Description with their dynamic counterparts: OptionsFunc, TitleFunc, and DescriptionFunc to recompute properties values on changes when watched variables change.

Let’s build a simple state / province picker.

var country string
var state string

The country select will be static, we’ll use this value to recompute the options and title for the next input.

huh.NewSelect[string]().
    Options(huh.NewOptions("United States", "Canada", "Mexico")...).
    Value(&country).
    Title("Country").

Define your Select with TitleFunc and OptionsFunc and bind them to the &country value from the previous field. Whenever the user chooses a different country, the TitleFunc and OptionsFunc will be recomputed.

[!IMPORTANT] We have to pass &country as the binding to recompute the function only when country changes, otherwise we will hit the API too often.

huh.NewSelect[string]().
    Value(&state).
    Height(8).
    TitleFunc(func() string {
        switch country {
        case "United States":
            return "State"
        case "Canada":
            return "Province"
        default:
            return "Territory"
        }
    }, &country).
    OptionsFunc(func() []huh.Option[string] {
        opts := fetchStatesForCountry(country)
        return huh.NewOptions(opts...)
    }, &country),

Lastly, run the form with these inputs.

err := form.Run()
if err != nil {
    log.Fatal(err)
}

maaslalani avatar May 10 '24 14:05 maaslalani

I first wanted to say, thank you for this work and this amazing library!

I was trying this out with a huh.Option[int] and was unable to get it to work, so I looked at the example which was working and I think I had finally tracked down what was going on for me:

https://github.com/charmbracelet/huh/blob/133f20570e4bebd877228739c5aa1eaf3a75f71b/group.go#L247-L257

It looks like the type switch only has updateOptionsMsg[string] in the case so other generic types do not match. I added updateOptionsMsg[int] just to see if it made it work and it seemed to yield the intended behavior. I hacked together something locally with an interface on updateOptionsMsg so that it could be more generally selected in that type switch, but unsure of the direction you all wanted to go. Happy to submit code or anything like that, if wanted, but also just wanted to make sure I pointed it out if that wasn't the intention to only support the string type of dynamic options.

Thanks again!

ChrisRx avatar May 14 '24 13:05 ChrisRx

@ChrisRx You're absolutely correct! This will definitely be fixed before merging / releasing. Thank you so much, really appreciate the review ❤️

maaslalani avatar May 14 '24 14:05 maaslalani

Really excited to see this make it into huh! Do we know when this PR will be merged?

shaunco avatar Jul 05 '24 20:07 shaunco

Really excited to see this make it into huh! Do we know when this PR will be merged?

I also want to know, I made the local clone and I'm going to test it on an internal CLI haha

OliveiraCleidson avatar Jul 06 '24 23:07 OliveiraCleidson