Skip to content

Commit

Permalink
fix: return inline errors for form
Browse files Browse the repository at this point in the history
  • Loading branch information
katallaxie authored Nov 6, 2024
1 parent 7821a8a commit ff28a61
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 1 deletion.
1 change: 1 addition & 0 deletions components/forms/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func TextInput(p TextInputProps, children ...htmx.Node) htmx.Node {
htmx.Attribute("name", p.Name),
htmx.Attribute("value", p.Value),
htmx.If(p.Disabled, htmx.Disabled()),
htmx.If(utilx.NotEmpty(p.Error), htmx.Attribute("aria-invalid", "true")),
htmx.Attribute("placeholder", p.Placeholder),
htmx.Group(children...),
)
Expand Down
6 changes: 6 additions & 0 deletions components/validate/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/go-playground/validator/v10"
"github.com/zeiss/pkg/slices"
"github.com/zeiss/pkg/utilx"
)

// Errors is a map of field names to error messages.
Expand All @@ -22,6 +23,11 @@ func (e Errors) Field(name string) string {
return ""
}

// HasError returns true if the field has an error.
func (e Errors) HasError(name string) bool {
return utilx.NotEmpty(e.Field(name))
}

// TagNameFunc returns the tag name for the provided field.
func TagNameFunc(fld reflect.StructField) string {
name := slices.First(strings.SplitN(fld.Tag.Get("json"), ",", 2)...)
Expand Down
73 changes: 72 additions & 1 deletion examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,56 @@ func init() {
rootCmd.SilenceUsage = true
}

type RegisterFormProps struct {
errors validate.Errors
}

func RegisterForm(props RegisterFormProps) htmx.Node {
return htmx.Form(
htmx.HxPost("/register"),
htmx.HxSwap("outerHTML"),
htmx.Target("cloesest div"),
forms.FormControl(
forms.FormControlProps{},
forms.FormControlLabel(
forms.FormControlLabelProps{},
forms.FormControlLabelText(
forms.FormControlLabelTextProps{
ClassNames: htmx.ClassNames{
"label-text": true,
},
},
htmx.Text("Email"),
),
),
forms.TextInput(
forms.TextInputProps{
Error: props.errors.Field("email"),
Name: "email",
Value: "Hello, World!",
},
htmx.Type("email"),
htmx.Required(),
),
htmx.If(
props.errors.HasError("email"),
htmx.Div(
htmx.ClassNames{
"text-error": true,
},
htmx.Text("A valid email is required."),
),
),
),
buttons.Button(
buttons.ButtonProps{
Type: "submit",
},
htmx.Text("Register"),
),
)
}

type exampleController struct {
htmx.UnimplementedController
}
Expand Down Expand Up @@ -419,7 +469,7 @@ func (c *exampleController) Get() error {
),
),
),

RegisterForm(RegisterFormProps{}),
alerts.Info(
alerts.AlertProps{},
htmx.Text("Hello, World!"),
Expand Down Expand Up @@ -712,6 +762,27 @@ func (w *webSrv) Start(ctx context.Context, ready server.ReadyFunc, run server.R
return &exampleController{}
}))

app.Post("/register", htmx.NewCompFuncHandler(func(c *fiber.Ctx) (htmx.Node, error) {
type Form struct {
Email string `json:"email" validate:"required,email"`
}

var f Form
if err := c.BodyParser(&f); err != nil {
return nil, err
}

v := validator.New()
v.RegisterTagNameFunc(validate.TagNameFunc)
if err := v.Struct(f); err != nil {
return RegisterForm(RegisterFormProps{
errors: validate.Errors(err.(validator.ValidationErrors)),
}), nil
}

return RegisterForm(RegisterFormProps{}), nil
}))

app.Post("/dropdown", htmx.NewCompHandler(
htmx.Fragment(
dropdowns.DropdownMenuItem(
Expand Down

0 comments on commit ff28a61

Please sign in to comment.