cicadel

Forms and validation

Forms declare the fields you accept, bind a submission and validate it. Use one for any browser form, like a Django Form.

Act on the data only after validation succeeds. Keep session and CSRF middleware around the handler.

#Ask your agent

Text
Read https://cicadel.fauzaanu.com/en/0.2.8/topics/forms-completion/index.md.
Add a form for [fields and validation rules] to my application.
Show field errors beside the controls and preserve non-sensitive submitted values.
Use the existing sessions and CSRF middleware. Test valid input, invalid input,
missing CSRF tokens and unexpected fields before connecting any side effects.

#Define fields

Create the definition once, during application setup. Handle configuration errors before you serve requests.

Go
package contact

import "github.com/fauzaanu/cicadel/forms"

func Definition() (*forms.Definition, error) {
    return forms.New([]forms.Field{
        forms.Text(forms.Options{
            Name: "email", Label: "Email", Widget: "email", Required: true,
        }, forms.Email),
        forms.Boolean(forms.Options{
            Name: "accepted", Label: "I agree to the terms",
        }, forms.Accepted),
    })
}

Only declared fields are bound. For other common inputs, use forms.Integer, forms.Number, forms.Date, forms.Select and forms.Multiple.

#Bind a submission

In your POST handler, after authentication and CSRF checks:

Go
r.Body = http.MaxBytesReader(w, r.Body, 8<<10)
posted, err := forms.Parse(r)
if err != nil {
    response.Error(w, http.StatusBadRequest)
    return
}
bound := definition.Bind(posted.Values)
if !bound.Valid() {
    // Render your form page with bound and status 422.
    renderForm(w, r, http.StatusUnprocessableEntity, bound)
    return
}
email, ok := forms.Value[string](bound, "email")
if !ok {
    response.Error(w, http.StatusInternalServerError)
    return
}
// Use email for the application's next step only after validation succeeds.
  • definition is the result of Definition().
  • renderForm is your page-rendering helper.
  • For a GET, render definition.Initial() instead.

Warning

Do not log submitted values or redisplay passwords.

#Render labels and errors

This component renders the bound fields. Pass a CSRF token from your existing session middleware.

templ
package contact

import "github.com/fauzaanu/cicadel/forms"
import "github.com/fauzaanu/cicadel/ui"
import "github.com/fauzaanu/cicadel/ui/form"

templ fields(bound *forms.Bound, csrfToken string) {
    <form method="post" action="/contact">
        @form.CSRF.Call(form.CSRFProps{Token: csrfToken}, ui.NoSlots{})
        for _, field := range bound.Fields() {
            @form.Field.Call(form.Bound(field, "contact-" + field.Name), ui.NoSlots{})
        }
        <button type="submit">Submit</button>
    </form>
}

The field component connects labels, help text and errors to the control. Show form-wide errors separately with bound.Errors()[""].

The component guide shows a complete handler and page-rendering flow.

#Save a model

Use model forms when accepted values create or update a GORM model. Define an allowlist of editable fields. Scope every update to records the current user may change.

#Stale edits

Reject an edit when someone else changed the record first:

  1. Add a Revision int64 column with a recorded migration.
  2. Set model.Config[T].VersionField to "Revision".
  3. Render form.Version(ctx, &record) in a hidden _version field.
  4. When a save returns model.ErrConflict, show a conflict message. Ask the user to reload before trying again.

#File fields and persistence

Use forms/upload for bounded multipart uploads.

  • Close each parsed batch.
  • Choose trusted storage keys.
  • Connect storage writes to your persistence operation.

The upload reference covers limits, validation, cleanup and middleware order.

#Admin integration

  • Use admin.Config[T].Model to supply model-form fields and validation.
  • Use the first-party formsets module for multiple rows and inline editing.

See the forms reference for field types, custom validators and transaction behavior.

Type to search this version.