Initial commit of form submission struct.
This commit is contained in:
parent
b61077dac9
commit
57159c4fba
91
controller/form.go
Normal file
91
controller/form.go
Normal file
@ -0,0 +1,91 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type FormSubmission struct {
|
||||
IsSubmitted bool
|
||||
|
||||
Errors map[string][]string
|
||||
}
|
||||
|
||||
func (f *FormSubmission) Process(ctx echo.Context, form interface{}) error {
|
||||
f.Errors = make(map[string][]string)
|
||||
f.IsSubmitted = true
|
||||
|
||||
// Validate the form
|
||||
if err := ctx.Validate(form); err != nil {
|
||||
f.setErrorMessages(form, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f FormSubmission) HasErrors() bool {
|
||||
if f.Errors == nil {
|
||||
return false
|
||||
}
|
||||
return len(f.Errors) > 0
|
||||
}
|
||||
|
||||
func (f FormSubmission) FieldHasError(fieldName string) bool {
|
||||
return len(f.GetFieldErrors(fieldName)) > 0
|
||||
}
|
||||
|
||||
func (f FormSubmission) GetFieldErrors(fieldName string) []string {
|
||||
if f.Errors == nil {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
errors, has := f.Errors[fieldName]
|
||||
if !has {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
func (f *FormSubmission) setErrorMessages(form interface{}, err error) {
|
||||
// Only this is supported right now
|
||||
ves, ok := err.(validator.ValidationErrors)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
formType := reflect.TypeOf(form)
|
||||
|
||||
for _, ve := range ves {
|
||||
var message string
|
||||
|
||||
// Default the field form name to the name of the struct field
|
||||
fieldName := ve.StructField()
|
||||
|
||||
// Attempt to get the form field name from the field's struct tag
|
||||
if field, ok := formType.FieldByName(ve.Field()); ok {
|
||||
if fieldNameTag := field.Tag.Get("form"); fieldNameTag != "" {
|
||||
fieldName = fieldNameTag
|
||||
}
|
||||
}
|
||||
|
||||
// Provide better error messages depending on the failed validation tag
|
||||
// This should be expanded as you use additional tags in your validation
|
||||
switch ve.Tag() {
|
||||
case "required":
|
||||
message = "This field is required."
|
||||
case "email":
|
||||
message = "Enter a valid email address."
|
||||
case "eqfield":
|
||||
message = "Does not match."
|
||||
default:
|
||||
message = "Invalid value."
|
||||
}
|
||||
|
||||
// Add the error
|
||||
f.Errors[fieldName] = append(f.Errors[fieldName], message)
|
||||
}
|
||||
}
|
@ -16,8 +16,9 @@ type (
|
||||
}
|
||||
|
||||
ContactForm struct {
|
||||
Email string `form:"email" validate:"required,email" label:"Email address"`
|
||||
Message string `form:"message" validate:"required" label:"Message"`
|
||||
Email string `form:"email" validate:"required,email"`
|
||||
Message string `form:"message" validate:"required"`
|
||||
Submission controller.FormSubmission
|
||||
}
|
||||
)
|
||||
|
||||
@ -36,28 +37,31 @@ func (c *Contact) Get(ctx echo.Context) error {
|
||||
}
|
||||
|
||||
func (c *Contact) Post(ctx echo.Context) error {
|
||||
fail := func(message string, err error) error {
|
||||
ctx.Logger().Errorf("%s: %v", message, err)
|
||||
msg.Danger(ctx, "An error occurred. Please try again.")
|
||||
return c.Get(ctx)
|
||||
}
|
||||
//fail := func(message string, err error) error {
|
||||
// ctx.Logger().Errorf("%s: %v", message, err)
|
||||
// msg.Danger(ctx, "An error occurred. Please try again.")
|
||||
// return c.Get(ctx)
|
||||
//}
|
||||
|
||||
// Parse the form values
|
||||
var form ContactForm
|
||||
if err := ctx.Bind(&form); err != nil {
|
||||
return fail("unable to parse contact form", err)
|
||||
ctx.Logger().Error(err)
|
||||
}
|
||||
|
||||
if err := form.Submission.Process(ctx, form); err != nil {
|
||||
// TOOD
|
||||
}
|
||||
|
||||
ctx.Set(context.FormKey, form)
|
||||
|
||||
// Validate the form
|
||||
if err := ctx.Validate(form); err != nil {
|
||||
c.SetValidationErrorMessages(ctx, err, form)
|
||||
if form.Submission.HasErrors() {
|
||||
return c.Get(ctx)
|
||||
}
|
||||
|
||||
p := controller.NewHTMX(ctx)
|
||||
htmx := controller.NewHTMXRequest(ctx)
|
||||
|
||||
if p.Request.Enabled {
|
||||
if htmx.Enabled {
|
||||
return ctx.String(http.StatusOK, "<b>HELLO!</b>")
|
||||
} else {
|
||||
msg.Success(ctx, "Thank you for contacting us!")
|
||||
|
@ -1,3 +1,9 @@
|
||||
{{define "csrf"}}
|
||||
<input type="hidden" name="csrf" value="{{.CSRF}}"/>
|
||||
{{end}}
|
||||
|
||||
{{define "form-field-errors"}}
|
||||
{{range .}}
|
||||
<p class="help is-danger">{{.}}</p>
|
||||
{{end}}
|
||||
{{end}}
|
@ -1,11 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="en" style="height:100%;">
|
||||
<head>
|
||||
{{template "metatags" .}}
|
||||
{{template "css" .}}
|
||||
{{template "js" .}}
|
||||
</head>
|
||||
<body>
|
||||
<body class="has-background-light" style="min-height:100%;">
|
||||
<nav class="navbar is-dark">
|
||||
<div class="container" hx-boost="true">
|
||||
<div class="navbar-brand">
|
||||
@ -28,12 +28,14 @@
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
{{- if .Title}}
|
||||
<h1 class="title">{{.Title}}</h1>
|
||||
{{- end}}
|
||||
<div class="box">
|
||||
{{- if .Title}}
|
||||
<h1 class="title">{{.Title}}</h1>
|
||||
{{- end}}
|
||||
|
||||
{{template "messages" .}}
|
||||
{{template "content" .}}
|
||||
{{template "messages" .}}
|
||||
{{template "content" .}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
|
@ -1,10 +1,11 @@
|
||||
{{define "content"}}
|
||||
<form id="contact" method="post" hx-post>
|
||||
<form id="contact" method="post" >
|
||||
<div class="field">
|
||||
<label for="email" class="label">Email address</label>
|
||||
<div class="control">
|
||||
<input id="email" name="email" type="email" class="input" value="{{.Data.Email}}">
|
||||
</div>
|
||||
{{template "form-field-errors" (.Data.Submission.GetFieldErrors "email")}}
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
@ -12,6 +13,7 @@
|
||||
<div class="control">
|
||||
<textarea id="message" name="message" class="textarea">{{.Data.Message}}</textarea>
|
||||
</div>
|
||||
{{template "form-field-errors" (.Data.Submission.GetFieldErrors "message")}}
|
||||
</div>
|
||||
|
||||
<div class="field is-grouped">
|
||||
|
Loading…
Reference in New Issue
Block a user