Views

Forms

Build model-aware form partials, field helpers, and REST method overrides.

By Guillermo Alvarez - Published - Updated

Form partials

GoLazy forms are intentionally partial-based. A page view calls form_for:

{{ form_for .Car . }}

For a Car model, GoLazy renders the form wrapper and then renders:

_car_form.html.tpl

Multiword model keys use underscored partial filenames, so RaceCar renders _race_car_form.html.tpl.

The partial receives the original view data plus form-specific values:

{{ text_field "Model" }}
{{ date_field "BuiltAt" }}
{{ checkbox_field "Active" }}
{{ submit_button "Save" }}

The active form is also available as .Form, and the model is available as .Model, .FormObject, and .FormData.

Field names

Field helpers ask golazy.dev/lazyschema for generated names and ids. This keeps rendering and decoding aligned.

For a model field path:

Phone.Label
Phones.0.Number
URLValue

GoLazy generates:

name="phone_label"
name="phones_0_number"
name="urlValue"

Ids include the model key as a prefix:

id="car_phone_label"

Use schema:"custom_name" on a struct field when the generated name needs an explicit override. Use schema:"-" or form:"-" to skip a field.

Decode requests

lazyschema is adapted from Gorilla schema and decodes form values into Go structs:

var car Car
decoder := lazyschema.NewDecoder()
if err := decoder.Decode(&car, r.PostForm); err != nil {
    return err
}

The decoder uses bounded defaults for key count, value count, key length, nesting depth, and slice size. Register converters for custom scalar types. time.Time accepts common HTML date, time, and datetime-local values by default.

Resource targets

Connect a model type to a REST resource:

router.Resources(cars.New, func(r *lazyroutes.Resource) {
    r.Model(Car{})
})

For new records, form_for targets the create route with POST. If the model implements:

type Resource interface {
    Persisted() bool
    RouteParam() string
}

persisted records target the update route with POST and a hidden _method=patch field.

Use option helpers when a form needs a manual target or HTML attributes:

{{ form_for .Car . (form_route "garage_car" .Car.Slug) }}
{{ form_for .Car . (form_action "/cars") (form_add_class "compact") }}
{{ form_for .Car . (form_scope "vehicle") (form_file "vehicle_fields") }}

Delete buttons

Use delete_button_for for a small delete form:

{{ delete_button_for .Car "Delete" }}

It renders a POST form with hidden _method=delete and targets the resource delete route.

Method override

HTML forms only submit GET and POST. GoLazy installs route-scoped method override middleware so a form can submit:

<input type="hidden" name="_method" value="patch">

Only routed POST form requests can override the method. The middleware accepts put, patch, and delete, skips upgrade requests, reads only a bounded prefix of the body, and replays that body for the controller.