huh icon indicating copy to clipboard operation
huh copied to clipboard

Feature Request: Validate on a Group

Open firefart opened this issue 1 year ago • 0 comments

Is your feature request related to a problem? Please describe. I have a form with multiple groups where the first group gathers credentials and the second group does an api call with it to display the result. I would like to verify the credentials (username and password) as a pair by doing a login when switching to the next group. Currently I can only validate each field on it's own which is not enough for a username and password pair.

Describe the solution you'd like It would be great to have a Validate function on the whole group that returns an error and renders the error message somewhere in the group. A spinner until the validation is finished would also be needed to have a nice user experience. In my case I would call a login api call to verify the credentials and only switch to the next group if they are valid.

Describe alternatives you've considered Using two separate forms with a huh.Spinner in between them, but I would prefer them in one single form

Additional context Example:

var username, password, apiresult string

f := huh.NewForm(
    // credentials
    huh.NewGroup(
	    huh.NewNote().Description("Please enter your credentials"),
	    huh.NewInput().Value(&username).Title("Username:").Validate(huh.ValidateMinLength(1)),
	    huh.NewInput().Value(&password).Title("Password:").Validate(huh.ValidateMinLength(1)),
    ),
    // fetch api
    huh.NewGroup(
	    huh.NewNote().Description("Select a value returned from the API:"),
	    huh.NewSelect[string]().
		    Title("API Result").
		    Value(&apiresult).
		    OptionsFunc(func() []huh.Option[string] {
			    time.Sleep(2 * time.Second)
			    return huh.NewOptions("a", "b")
		    }, nil),
    ),
)
err = f.Run()
    if err != nil {
    return err
}

Example with a Validator and exposed fields on a Group:

f := huh.NewForm(
    // credentials
    huh.NewGroup(
	    huh.NewNote().Description("Please enter your credentials"),
	    huh.NewInput().Key("username").Value(&username).Title("Username:").Validate(huh.ValidateMinLength(1)),
	    huh.NewInput().Key("password").Value(&password).Title("Password:").Validate(huh.ValidateMinLength(1)),
    ).Validate(func(g huh.Group) error {
        username := g.GetString("username")
        password := g.GetString("password")
        // verify login
        time.Sleep(2 * time.Second)
        return fmt.Errorf("Invalid credentials")
    }),
    // fetch api
    huh.NewGroup(
	    huh.NewNote().Description("Select a value returned from the API:"),
	    huh.NewSelect[string]().
		    Title("API Result").
		    Value(&apiresult).
		    OptionsFunc(func() []huh.Option[string] {
			    time.Sleep(2 * time.Second)
			    return huh.NewOptions("a", "b")
		    }, nil),
    ),
)
err = f.Run()
    if err != nil {
    return err
}

firefart avatar Aug 23 '24 15:08 firefart