aform

package module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 13, 2022 License: MIT Imports: 21 Imported by: 0

README

aform

Go Reference CircleCI

Package aform provides functionalities for working effectively with forms.

Documentation

Overview

Package aform provides functionalities for working effectively with forms.

Introduction

This package provides simple tools to create forms, to render them as HTML and to do forms' input validations.

Let's suppose you want to create a form to get the user's name. You'll need something like this in your template.

<form action="/your-name" method="post">
	<label for="your_name">Your name: </label>
	<input id="your_name" type="text" name="your_name" value="{{ .CurrentName }}">
	<input type="submit" value="OK">
</form>

This HTML code tells the browser to return the form data to the URL /your-name, using the POST method. It will display a text field labeled "Your name:" and a button "OK". If the template context contains the CurrentName variable, it will be used to pre-fill the your_name field.

You'll need a handler to render the template containing the HTML form and providing the CurrentName value.

When the form is submitted, the POST request which is sent to the server will contain the form data. So, you'll also need a handler for the POST request to the path /your-name. This handler will have to find the appropriate key/values pairs in the request and to process them.

Form Creation

We already know what we want our HTML form to look like. Our starting point to create it with aform is this:

nameForm := aform.Must(aform.New(
	aform.WithCharField(aform.Must(aform.DefaultCharField("Your name"))),
))

This creates a Form with a single CharField. We used DefaultCharField that creates a CharField with reasonable defaults like a maximum length of 256. It means that the browser should prevent the user from entering more characters than that. It also means that when your application HTTP handler receives the form back from the browser, aform will validate the length of the data.

A Form has a Form.IsValid function, which runs validation for all its fields. When this function is called, if all fields contain valid data, it will return true and make the form's data accessible via Form.CleanedData function.

The whole nameForm, when rendered for the first time, will look like:

<div><label for="id_your_name">Your name</label><input type="text" name="your_name" id="id_your_name" maxlength="256" required></div>

Note that it does not include the <form> tags, or a submit button. We’ll have to provide those ourselves in the template.

The HTTP handler

Form data sent back to the server is processed by a handler. To handle the form we need to create the form in the handler for the path where we want it to be published:

func nameHandler(w http.ResponseWriter, req *http.Request) {
	nameForm := aform.Must(aform.New(
		aform.WithCharField(aform.Must(aform.DefaultCharField("Your name"))),
	))
	// if this is a POST request we need to process the form data
	if req.Method == "POST" {
		// Populate the form with data from the request:
		nameForm.BindRequest(req)
		// check whether it's valid:
		if nameForm.IsValid() {
			// process the data with Form.CleanedData
			// ...
			// redirect to a new URL:
			http.Redirect(w, req, "/congratulations", http.StatusFound)
		}
	}
	_ = tmpl.ExecuteTemplate(w, "name", map[string]any{"form": nameForm})
}

If the handler is triggered by a GET request, it will create an empty form and place it in the template context to be rendered. This is what we can expect to happen the first time we visit the URL.

If the form is submitted using a POST request, the handler will populate the form with data from the request:

nameForm.BindRequest(req)

This is called “binding data to the form” (it is now a bound form).

We call the Form.IsValid method; if it’s not True, we go back to the template with the form. This time the form is no longer empty (unbound) so the HTML form will be populated with the data previously submitted, where it can be edited and corrected as required. The HTML form will also display errors found by the validation.

If Form.IsValid is True, we’ll now be able to find all the validated form data in its CleanedData returned by Form.CleanedData. We can use this data to update the database or do other processing before sending an HTTP redirect to the browser telling it where to go next.

The template

We don’t need to do much in our template:

<form action="/your-name" method="post">
	{{ .form.AsDiv }}
	{{/* Add CSRF */}}
	<button type="submit">OK</button>
</form>

All the form’s fields and their attributes will be unpacked into HTML markup from that:

{{ .form.AsDiv }}

Bound and unbound forms

A Form is either bound to a set of data, or unbound. If it’s bound to a set of data, it’s capable of validating that data and rendering the form as HTML with the data displayed in the HTML. If it’s unbound, it cannot do validation (because there’s no data to validate), but it can still render the blank form as HTML.

To bind a Form, we use the method Form.BindRequest. Method Form.BindData can be used too, when the application needs to modify the default behavior.

Example (YourName)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
	"html/template"
	"net/http"
)

func main() {
	http.HandleFunc("/your-name", nameHandler)
	http.HandleFunc("/congratulations", congratulationsHandler)
	panic(http.ListenAndServe(":8080", nil))
}

func nameHandler(w http.ResponseWriter, req *http.Request) {
	nameForm := aform.Must(aform.New(
		aform.WithCharField(aform.Must(aform.DefaultCharField("Your name"))),
	))
	// if this is a POST request we need to process the form data
	if req.Method == "POST" {
		// Populate the form with data from the request:
		nameForm.BindRequest(req)
		// check whether it's valid:
		if nameForm.IsValid() {
			// process the data with Form.CleanedData
			// ...
			// redirect to a new URL:
			http.Redirect(w, req, "/congratulations", http.StatusFound)
		}
	}
	_ = tmpl.ExecuteTemplate(w, "name", map[string]any{"form": nameForm})
}

var tmpl = template.Must(template.New("name").Parse(tmplBody))

const tmplBody = `<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Name Form</title>
	</head>
	<body>
		<form action="/your-name" method="post">
			{{ .form.AsDiv }}
			{{/* Add CSRF */}}
			<button type="submit">OK</button>
		</form>
	</body>
</html>`

func congratulationsHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintln(w, "Congratulations!")
}
Output:

Index

Examples

Constants

View Source
const (
	BooleanErrorCode   = "boolean"
	EmailErrorCode     = "email"
	ChoiceErrorCode    = "oneof"
	MinLengthErrorCode = "min"
	MaxLengthErrorCode = "max"
	RequiredErrorCode  = "required"
	URLErrorCode       = "url"
)

Error codes of the available validations. Each validation has a code and a default message. Example: If a BooleanField value is not a boolean, the validation returns an error with the code BooleanErrorCode and the default message BooleanErrorMessageEn. Error messages can be modified with the function Field.CustomizeError.

View Source
const (
	BooleanFieldType        = FieldType("BooleanField")
	CharFieldType           = FieldType("CharField")
	EmailFieldType          = FieldType("EmailField")
	URLFieldType            = FieldType("URLField")
	ChoiceFieldType         = FieldType("ChoiceField")
	MultipleChoiceFieldType = FieldType("MultipleChoiceField")
)

Field types available. Each of them has its own creation interface. For instance to create a BooleanFieldType, you can use NewBooleanField or DefaultBooleanField functions.

View Source
const (
	BooleanErrorMessageEn   = "Enter a valid boolean"
	EmailErrorMessageEn     = "Enter a valid email address"
	ChoiceErrorMessageEn    = "Invalid choice"
	MinLengthErrorMessageEn = "Ensure this value has at least {0} characters"
	MaxLengthErrorMessageEn = "Ensure this value has at most {0} characters"
	RequiredErrorMessageEn  = "This field is required"
	URLErrorMessageEn       = "Enter a valid URL"
)

English error messages of the available validations.

View Source
const (
	BooleanErrorMessageFr   = "Entrez un booléen valide"
	EmailErrorMessageFr     = "Entrez une adresse e-mail valide"
	ChoiceErrorMessageFr    = "Choix invalide"
	MinLengthErrorMessageFr = "Assurez-vous que cette valeur fait au minimum {0} caractères"
	MaxLengthErrorMessageFr = "Assurez-vous que cette valeur fait au maximum {0} caractères"
	RequiredErrorMessageFr  = "Ce champ est obligatoire"
	URLErrorMessageFr       = "Entrez une URL valide"
)

French error messages of the available validations.

View Source
const (
	// TextInput renders as: <input type="text" ...>
	TextInput = Widget("TextInput")
	// EmailInput renders as: <input type="email" ...>
	EmailInput = Widget("EmailInput")
	// URLInput renders as: <input type="url" ...>
	URLInput = Widget("URLInput")
	// PasswordInput renders as: <input type="password" ...>
	PasswordInput = Widget("PasswordInput")
	// HiddenInput renders as: <input type="hidden" ...>
	HiddenInput = Widget("HiddenInput")
	// TextArea renders as: <textarea>...</textarea>
	TextArea = Widget("TextArea")
	// CheckboxInput renders as: <input type="checkbox" ...>
	CheckboxInput = Widget("CheckboxInput")
	// Select renders as: <select><option ...>...</select>
	Select = Widget("Select")
	// SelectMultiple renders as Select but allow multiple selection: <select multiple>...<	/select>
	SelectMultiple = Widget("SelectMultiple")
	// RadioSelect is similar to Select, but rendered as a list of radio buttons within <div> tags:
	// 	<div>
	//    <div><input type="radio" name="..."></div>
	//    ...
	// 	</div>
	RadioSelect = Widget("RadioSelect")
	// CheckboxSelectMultiple is similar SelectMultiple, but rendered as a list of checkboxes
	// 	<div>
	//    <div><input type="checkbox" name="..." ></div>
	//    ...
	// 	</div>
	CheckboxSelectMultiple = Widget("CheckboxSelectMultiple")
)

Widgets are used by the fields to handle HTML rendering. Each field as a default widget. It can be changed with WithWidget or SetWidget functions.

Variables

This section is empty.

Functions

func Must

func Must[FormPtrFieldPtr FormPointerOrFieldPointer](f FormPtrFieldPtr, err error) FormPtrFieldPtr

Must is a helper that wraps a call to a function returning (*Form, error) or (*Field, error) and panics if the error is non-nil. It is intended for use in form creations. e.g.

var fld = Must(DefaultCharField("Name"))
var f = Must(New(WithCharField(fld)))

Types

type AttrName

type AttrName interface {
	~string
}

AttrName defines the HTML attribute name type

type AttrValue

type AttrValue interface {
	constraints.Integer | ~string
}

AttrValue defines the HTML attribute value type

type Attributable

type Attributable interface {
	// contains filtered or unexported methods
}

Attributable defines a common interface for name/value HTML attributes and boolean HTML attributes.

func Attr

func Attr[N AttrName, V AttrValue](name N, value V) Attributable

Attr returns an HTML attribute named name and that is equal to value. Example to add attribute placeholder="****"

Attr("placeholder", "****")

Example to add attribute maxlength="125"

Attr("maxlength", 125)

func BoolAttr

func BoolAttr[N AttrName](name N) Attributable

BoolAttr returns a boolean HTML attribute named name. Example to add attribute readonly

BoolAttr("readonly")

type BooleanField

type BooleanField struct {
	*Field
	// contains filtered or unexported fields
}

BooleanField is a field type that validates that the given value is a valid boolean.

func DefaultBooleanField

func DefaultBooleanField(name string, opts ...FieldOption) (*BooleanField, error)

DefaultBooleanField creates a boolean field with reasonable default values. The initial parameter value is false.

func NewBooleanField

func NewBooleanField(name string, initial bool, opts ...FieldOption) (*BooleanField, error)

NewBooleanField creates a boolean field named name. The parameter initial is the initial value before data bounding. The default Widget is CheckboxInput. To change it, use WithWidget or SetWidget.

func (*BooleanField) Clean

func (fld *BooleanField) Clean(value string) (string, []Error)

Clean returns the cleaned value. value is first sanitized and finally validated. Sanitization can be customized with Field.SetSanitizeFunc. Validation can be customized with Field.SetValidateFunc.

func (*BooleanField) EmptyValue

func (fld *BooleanField) EmptyValue() string

EmptyValue returns the BooleanField empty value. The empty value is the cleaned value returned by Clean when there is no data bound to the field. A BooleanField empty value is always "off".

func (*BooleanField) MustBoolean

func (fld *BooleanField) MustBoolean(value string) bool

MustBoolean returns the clean value type cast to bool. It panics if the value provided is not a valid boolean input.

type CharField

type CharField struct {
	*Field
	// contains filtered or unexported fields
}

CharField is a field type that doesn't do semantic validation on the given value.

func DefaultCharField

func DefaultCharField(name string, opts ...FieldOption) (*CharField, error)

DefaultCharField creates a char field with reasonable default values. initial and empty parameters are the empty string. min length is 0 and max length is 256.

Example (PasswordWithPlaceholder)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultCharField(
		"Password",
		aform.WithWidget(aform.PasswordInput),
		aform.WithAttributes([]aform.Attributable{aform.Attr("placeholder", "****")})))
	fmt.Println(fld.AsDiv())
}
Output:

<div><label for="id_password">Password</label><input type="password" name="password" id="id_password" maxlength="256" placeholder="****" required></div>

func NewCharField

func NewCharField(name, initial, empty string, min, max uint, opts ...FieldOption) (*CharField, error)

NewCharField creates a char field named name. The parameter initial is the initial value before data bounding. The parameter empty is the cleaned data value when there is no data bound to the field. If the parameter min (respectively max) is not 0, it validates that the input value is longer or equal than min (respectively shorter or equal than max). Otherwise, all inputs are valid. The default Widget is TextInput. To change it, use WithWidget or SetWidget.

Example (PasswordWithPlaceholder)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.NewCharField("Password", "", "", 0, 0,
		aform.WithWidget(aform.PasswordInput),
		aform.WithAttributes([]aform.Attributable{aform.Attr("placeholder", "****")})))
	fmt.Println(fld.AsDiv())
}
Output:

<div><label for="id_password">Password</label><input type="password" name="password" id="id_password" placeholder="****" required></div>
Example (WithInitialValue)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.NewCharField("Your color", "white", "", 0, 0))
	fmt.Println(fld.AsDiv())
}
Output:

<div><label for="id_your_color">Your color</label><input type="text" name="your_color" value="white" id="id_your_color" required></div>

func (*CharField) Clean

func (fld *CharField) Clean(value string) (string, []Error)

Clean returns the cleaned value. value is first sanitized and finally validated. Sanitization can be customized with Field.SetSanitizeFunc. Validation can be customized with Field.SetValidateFunc.

func (*CharField) EmptyValue

func (fld *CharField) EmptyValue() string

EmptyValue returns the CharField empty value. The empty value is the cleaned value returned by Clean when there is no data bound to the field. To set a custom empty value use NewCharField.

type ChoiceField

type ChoiceField struct {
	*Field
	// contains filtered or unexported fields
}

ChoiceField is a field type that validates that the given value is one of the options listed with WithChoiceOptions or WithGroupedChoiceOptions.

func DefaultChoiceField

func DefaultChoiceField(name string, opts ...FieldOption) (*ChoiceField, error)

DefaultChoiceField creates a choice field with reasonable default values. initial parameter is the empty string. To add options use WithChoiceOptions or WithGroupedChoiceOptions.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(
		aform.DefaultChoiceField("Color",
			aform.WithChoiceOptions([]aform.ChoiceFieldOption{
				{Value: "red", Label: "Rouge"},
				{Value: "green", Label: "Vert"},
				{Value: "blue", Label: "Bleu"},
			}),
		),
	)
	fmt.Println(fld.AsDiv())
}
Output:

<div><label for="id_color">Color</label><select name="color" id="id_color" required>
  <option value="red" id="id_color_0">Rouge</option>
  <option value="green" id="id_color_1">Vert</option>
  <option value="blue" id="id_color_2">Bleu</option>
</select></div>
Example (WithRadio)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(
		aform.DefaultChoiceField("Color",
			aform.WithWidget(aform.RadioSelect),
			aform.WithChoiceOptions([]aform.ChoiceFieldOption{
				{Value: "red", Label: "Rouge"},
				{Value: "green", Label: "Vert"},
				{Value: "blue", Label: "Bleu"},
			}),
		),
	)
	fmt.Println(fld.AsDiv())
}
Output:

<div>
<fieldset><legend for="id_color">Color</legend>
<div id="id_color">
<label for="id_color_0"><input type="radio" name="color" value="red" id="id_color_0">Rouge</label>
<label for="id_color_1"><input type="radio" name="color" value="green" id="id_color_1">Vert</label>
<label for="id_color_2"><input type="radio" name="color" value="blue" id="id_color_2">Bleu</label>
</div>
</fieldset>
</div>

func NewChoiceField

func NewChoiceField(name, initial string, opts ...FieldOption) (*ChoiceField, error)

NewChoiceField creates a choice field named name. The parameter initial is the initial value before data bounding. To add options use WithChoiceOptions or WithGroupedChoiceOptions. The default Widget is Select. To change it, use WithWidget or Field.SetWidget.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(
		aform.NewChoiceField("Color", "",
			aform.WithChoiceOptions([]aform.ChoiceFieldOption{{Value: "red", Label: "Rouge"}, {Value: "green", Label: "Vert"},
				{Value: "blue", Label: "Bleu"},
			}),
		),
	)
	fmt.Println(fld.AsDiv())
}
Output:

<div><label for="id_color">Color</label><select name="color" id="id_color" required>
  <option value="red" id="id_color_0">Rouge</option>
  <option value="green" id="id_color_1">Vert</option>
  <option value="blue" id="id_color_2">Bleu</option>
</select></div>
Example (WithRadio)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(
		aform.NewChoiceField("Color", "",
			aform.WithWidget(aform.RadioSelect),
			aform.WithChoiceOptions([]aform.ChoiceFieldOption{
				{Value: "red", Label: "Rouge"},
				{Value: "green", Label: "Vert"},
				{Value: "blue", Label: "Bleu"},
			}),
		),
	)
	fmt.Println(fld.AsDiv())
}
Output:

<div>
<fieldset><legend for="id_color">Color</legend>
<div id="id_color">
<label for="id_color_0"><input type="radio" name="color" value="red" id="id_color_0">Rouge</label>
<label for="id_color_1"><input type="radio" name="color" value="green" id="id_color_1">Vert</label>
<label for="id_color_2"><input type="radio" name="color" value="blue" id="id_color_2">Bleu</label>
</div>
</fieldset>
</div>

func (*ChoiceField) Clean

func (fld *ChoiceField) Clean(value string) (string, []Error)

Clean returns the cleaned value. value is first sanitized and finally validated. Sanitization can be customized with Field.SetSanitizeFunc. Validation can be customized with Field.SetValidateFunc.

func (*ChoiceField) EmptyValue

func (fld *ChoiceField) EmptyValue() string

EmptyValue returns the ChoiceField empty value. The empty value is the cleaned value returned by Clean when there is no data bound to the field. A ChoiceField empty value is always the empty string "".

type ChoiceFieldOption

type ChoiceFieldOption struct {
	Value string
	Label string
}

type CleanedData

type CleanedData map[string][]string

CleanedData maps a field normalized name to the list of bound data after validation

func (CleanedData) Get

func (d CleanedData) Get(field string) string

Get gets the first cleaned data associated with the given field. If there are no cleaned data associated with the field, Get returns the empty string. If the field accepts multiple data, use the map directly to access all of them.

func (CleanedData) Has

func (d CleanedData) Has(field string) bool

Has checks whether a given field has at least one cleaned data.

type EmailField

type EmailField struct {
	*Field
	// contains filtered or unexported fields
}

EmailField is a field type that validates that the given value is a valid email address.

func DefaultEmailField

func DefaultEmailField(name string, opts ...FieldOption) (*EmailField, error)

DefaultEmailField creates an email field with reasonable default values. initial and empty parameters are the empty string. min length is 0 and max length is 254.

func NewEmailField

func NewEmailField(name, initial, empty string, min, max uint, opts ...FieldOption) (*EmailField, error)

NewEmailField creates an email field named name. The parameter initial is the initial value before data bounding. The parameter empty is the cleaned data value when there is no data bound to the field. If the parameter min (respectively max) is not 0, it validates that the input value is longer or equal than min (respectively shorter or equal than max). The default Widget is EmailInput. To change it, use WithWidget or SetWidget.

func (*EmailField) Clean

func (fld *EmailField) Clean(value string) (string, []Error)

Clean returns the cleaned value. value is first sanitized and finally validated. Sanitization can be customized with Field.SetSanitizeFunc. Validation can be customized with Field.SetValidateFunc.

func (*EmailField) EmptyValue

func (fld *EmailField) EmptyValue() string

EmptyValue returns the EmailField empty value. The empty value is the cleaned value returned by Clean when there is no data bound to the field. To set a custom empty value use NewEmailField.

func (*EmailField) MustEmail

func (fld *EmailField) MustEmail(value string) string

MustEmail returns the clean value if the value provided is a valid email. Otherwise, it panics.

type Error

type Error struct {
	// contains filtered or unexported fields
}

Error defines errors returned by the forms validations. It implements ErrorCoderTranslator to help the customization of existing errors or the addition of application specific errors. To customize existing validation error messages use Field.CustomizeError. To add application specific errors at the form level use SetCleanFunc and at the field level Field.SetValidateFunc.

func ErrorWrap

func ErrorWrap(err error) Error

ErrorWrap wraps an error in a validation Error. It makes possible to use any error as a validation Error.

func ErrorWrapWithCode

func ErrorWrapWithCode(err error, code string) Error

ErrorWrapWithCode is like ErrorWrap and set or update the Error code.

func (Error) Code

func (e Error) Code() string

Code returns the code of the error.

func (Error) Error

func (e Error) Error() string

func (Error) Translate

func (e Error) Translate(locale string) string

Translate translates error messages. locale is a BCP 47 language tag.

func (Error) Unwrap

func (e Error) Unwrap() error

type ErrorCoderTranslator

type ErrorCoderTranslator interface {
	error
	Code() string
	Translate(locale string) string
}

ErrorCoderTranslator defines the validation errors interface.

type Field

type Field struct {
	// contains filtered or unexported fields
}

Field is the type grouping features shared by all field types.

func (*Field) AddChoiceOptions

func (fld *Field) AddChoiceOptions(label string, options []ChoiceFieldOption)

AddChoiceOptions adds a list of ChoiceFieldOption to the Field. if the parameter label is the empty string options are not grouped together. Example without group label:

fld.AddChoiceOptions("", []ChoiceFieldOption{{Value: "red", Label: "Rouge"}, {Value: "green", Label: "Vert"}})
// HTML output:
// <option value="red" id="id_color_0">Rouge</option>
// <option value="green" id="id_color_1">Vert</option>

Example with group label:

fld.AddChoiceOptions("RG", []ChoiceFieldOption{{Value: "red", Label: "Rouge"}, {Value: "green", Label: "Vert"}})
// HTML output:
//  <optgroup label="RG">
//    <option value="red" id="id_color_0_0">Rouge</option>
//    <option value="green" id="id_color_0_1">Vert</option>
//  </optgroup>

func (*Field) AsDiv

func (fld *Field) AsDiv() template.HTML

AsDiv renders the field in a <div> tag.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultCharField("Name"))
	fmt.Println(fld.AsDiv())
}
Output:

<div><label for="id_name">Name</label><input type="text" name="name" id="id_name" maxlength="256" required></div>
Example (WithHelpTextAndError)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultCharField("Name"))
	fld.SetHelpText("Please, enter your name")
	fld.Clean("")
	fmt.Println(fld.AsDiv())
}
Output:

<div><label for="id_name">Name</label>
<ul class="errorlist"><li id="err_0_id_name">This field is required</li></ul>
<input type="text" name="name" id="id_name" maxlength="256" aria-describedby="helptext_id_name err_0_id_name" aria-invalid="true" required>
<span class="helptext" id="helptext_id_name">Please, enter your name</span></div>

func (*Field) AutoID

func (fld *Field) AutoID() string

AutoID returns the auto ID set with SetAutoID.

func (*Field) CSSClasses

func (fld *Field) CSSClasses() string

func (*Field) CustomizeError

func (fld *Field) CustomizeError(err ErrorCoderTranslator)

CustomizeError replaces one built-in Error with err, if err ErrorCoderTranslator.Code matches one of the existing Error code. Existing Error codes are BooleanErrorCode, EmailErrorCode, ChoiceErrorCode, MinLengthErrorCode, MaxLengthErrorCode, RequiredErrorCode and URLErrorCode. If err ErrorCoderTranslator.Code is not from this list, it panics.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.NewCharField("Name", "", "", 10, 0))
	fld.CustomizeError(aform.ErrorWrapWithCode(fmt.Errorf("Please, enter enough characters"), aform.MinLengthErrorCode))
	fld.Clean("too_short")
	fmt.Println(fld.AsDiv())
}
Output:

<div><label for="id_name">Name</label>
<ul class="errorlist"><li id="err_0_id_name">Please, enter enough characters</li></ul>
<input type="text" name="name" value="too_short" id="id_name" minlength="10" aria-describedby="err_0_id_name" aria-invalid="true" required></div>

func (*Field) Errors

func (fld *Field) Errors() template.HTML

Errors renders field errors in a <ul> tag with each <li> children tag containing one error. CSS class errorlist is set on the <ul> tag. Each <li> tag as a generated unique ID based on the error index and the field ID.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultCharField("Name"))
	fld.Clean("")
	fmt.Println(fld.Errors())
}
Output:

<ul class="errorlist"><li id="err_0_id_name">This field is required</li></ul>
Example (WithoutErrors)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultCharField("Name"))
	fld.Clean("Paul")
	fmt.Printf("It renders the empty string: \"%s\"", fld.Errors())
}
Output:

It renders the empty string: ""

func (*Field) HTMLName

func (fld *Field) HTMLName() string

HTMLName returns the field's name transformed to be the value of the HTML name attribute.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultBooleanField("Remember me"))
	fmt.Println(fld.HTMLName())
}
Output:

remember_me

func (*Field) HasErrors

func (fld *Field) HasErrors() bool

HasErrors returns true if an input is bound to the field and there is a validation error.

func (*Field) HasHelpText

func (fld *Field) HasHelpText() bool

HasHelpText returns true if a help text has been added to the field.

func (*Field) HelpText

func (fld *Field) HelpText() template.HTML

HelpText renders the help text in a <span> tag. CSS class helptext and an ID generated from the field ID are set on the <span> tag.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultCharField("Name"))
	fld.SetHelpText("Please, enter your name")
	fmt.Println(fld.HelpText())
}
Output:

<span class="helptext" id="helptext_id_name">Please, enter your name</span>

func (*Field) LabelSuffix

func (fld *Field) LabelSuffix() string

LabelSuffix returns the suffix set with SetLabelSuffix.

func (*Field) LabelTag

func (fld *Field) LabelTag() template.HTML

LabelTag renders the <label> tag.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultCharField("Name"))
	fmt.Println(fld.LabelTag())
}
Output:

<label for="id_name">Name</label>

func (*Field) LegendTag

func (fld *Field) LegendTag() template.HTML

LegendTag renders the <legend> tag. This tag replaces <label> tag when a <fieldset> tag is used to group together options of fields using RadioSelect widget or CheckboxSelectMultiple widget.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultCharField("Name"))
	fmt.Println(fld.LegendTag())
}
Output:

<legend for="id_name">Name</legend>

func (*Field) MarkSafe

func (fld *Field) MarkSafe()

MarkSafe marks the field label as safe for HTML. It means the label and the label suffix are no more HTML-escaped.

func (*Field) Name

func (fld *Field) Name() string

Name returns the name given to the field.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultBooleanField("Remember me"))
	fmt.Println(fld.Name())
}
Output:

Remember me

func (*Field) Required

func (fld *Field) Required() bool

Required returns true if the field is required

func (*Field) SetAttributes

func (fld *Field) SetAttributes(attrs []Attributable)

SetAttributes adds custom attributes to the Widget. See WithAttributes for details.

func (*Field) SetAutoID

func (fld *Field) SetAutoID(autoID string) error

SetAutoID sets the string used to build the HTML ID. See WithAutoID for details on valid values.

func (*Field) SetDisabled

func (fld *Field) SetDisabled()

SetDisabled sets the Field as disabled.

func (*Field) SetErrorCSSClass

func (fld *Field) SetErrorCSSClass(class string)

SetErrorCSSClass sets a CSS class added to the HTML when the field has a validation error. To set the same error class to all fields in a form use WithErrorCSSClass.

func (*Field) SetHelpText

func (fld *Field) SetHelpText(help string)

SetHelpText adds a help text to the Field. Help text is not HTML-escaped.

func (*Field) SetLabel

func (fld *Field) SetLabel(label string)

SetLabel overrides the default label of the Field. By default, the label is the name of the Field given as parameter to a Field creation function. The label is HTML-escaped. To alter more the for= attribute or to completely remove the tag <label> use SetAutoID.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultBooleanField("remember"))
	fld.SetLabel("Remember me")
	fmt.Println(fld.LabelTag())
}
Output:

<label for="id_remember">Remember me</label>

func (*Field) SetLabelSuffix

func (fld *Field) SetLabelSuffix(labelSuffix string)

SetLabelSuffix sets a string appended to the label. To set the same suffix to all fields in a form use WithLabelSuffix.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultBooleanField("Remember me"))
	fld.SetLabelSuffix(":")
	fmt.Println(fld.LabelTag())
}
Output:

<label for="id_remember_me">Remember me:</label>

func (*Field) SetLocale

func (fld *Field) SetLocale(locale language.Tag)

SetLocale changes the locale used by the field to translate error messages. To set the same locale to all fields in a form use WithLocales.

func (*Field) SetNotRequired

func (fld *Field) SetNotRequired()

SetNotRequired sets the Field as not required. By default, all fields are required.

func (*Field) SetRequiredCSSClass

func (fld *Field) SetRequiredCSSClass(class string)

SetRequiredCSSClass sets a CSS class added to the HTML if the field is required. To set the same required class to all fields in a form use WithRequiredCSSClass.

func (*Field) SetSanitizeFunc

func (fld *Field) SetSanitizeFunc(update func(current SanitizationFunc) (new SanitizationFunc))

SetSanitizeFunc sets sanitization function. Parameter update is a function that itself has current sanitization function as parameter and must return the new sanitization function. Default sanitization function removes HTML elements, leading and trailing white characters. It removes as well new lines if the widget is not TextArea.

func (*Field) SetValidateFunc

func (fld *Field) SetValidateFunc(update func(current ValidationFunc) (new ValidationFunc))

SetValidateFunc sets validation function. Parameter update is a function that itself has current validation function as parameter and must return the new validation function. Default validation function depends on the field type.

func (*Field) SetWidget

func (fld *Field) SetWidget(widget Widget)

SetWidget changes the widget to the field. See WithWidget for examples.

func (*Field) Type

func (fld *Field) Type() FieldType

Type returns the Field type.

func (*Field) UseFieldset

func (fld *Field) UseFieldset() bool

UseFieldset returns true if the widget used by the field

func (*Field) Widget

func (fld *Field) Widget() template.HTML

Widget renders the widget.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(aform.DefaultCharField("Name"))
	fmt.Println(fld.Widget())
}
Output:

<input type="text" name="name" id="id_name" maxlength="256" required>

type FieldOption

type FieldOption func(*Field) error

FieldOption describes a functional option for configuring a Field.

func IsDisabled

func IsDisabled() FieldOption

IsDisabled returns a FieldOption that sets the Field as disabled.

func IsNotRequired

func IsNotRequired() FieldOption

IsNotRequired returns a FieldOption that sets the Field as not required. By default, all fields are required.

func IsSafe

func IsSafe() FieldOption

IsSafe returns a FieldOption that sets the Field as HTML safe. When a field is marked as safe, its label and label suffix are not HTML-escaped.

func WithAttributes

func WithAttributes(attrs []Attributable) FieldOption

WithAttributes returns a FieldOption that adds custom attributes to the Widget. For all the attributes but the class attribute, values set with this function override the values set by any other logic. If the class attribute is set, the error class set with the function SetErrorCSSClass is concatenated at the beginning. Three attribute names panic: type, name and value. To change the type, use a different Field and/or set a different Widget on an existing Field. To change the name attribute, set a different name to the Field when you create it. To change the value attribute, set an initial value when you create the field or bind values with BindRequest or BindData functions.

Example (ClassWithErrorClass)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	f := aform.Must(aform.New(
		aform.WithRequiredCSSClass("required"),
		aform.WithErrorCSSClass("error"),
		aform.WithCharField(aform.Must(aform.DefaultCharField(
			"Name",
			aform.WithAttributes([]aform.Attributable{aform.Attr("class", "big blue")}),
		))),
	))
	// Bind empty data. As the field is required,
	// it will make IsValid == false and add error to the HTML generated.
	f.BindData(map[string][]string{})
	// Run the form validation
	f.IsValid()
	fmt.Println(f.AsDiv())
}
Output:

<div class="required error"><label class="required" for="id_name">Name</label>
<ul class="errorlist"><li id="err_0_id_name">This field is required</li></ul>
<input type="text" name="name" class="error big blue" id="id_name" maxlength="256" aria-describedby="err_0_id_name" aria-invalid="true" required></div>

func WithChoiceOptions

func WithChoiceOptions(options []ChoiceFieldOption) FieldOption

WithChoiceOptions returns a FieldOption that adds a list of ChoiceFieldOption to the Field. This option is used only by fields presenting a list of choices like ChoiceField and MultipleChoiceField.

func WithGroupedChoiceOptions

func WithGroupedChoiceOptions(label string, options []ChoiceFieldOption) FieldOption

WithGroupedChoiceOptions returns a FieldOption that adds a list of ChoiceFieldOption grouped together in a <optgroup> tag. Parameter label is the value of the <optgroup> attribute label. This option is used only by fields presenting a list of choices like ChoiceField and MultipleChoiceField.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(
		aform.DefaultChoiceField("Color",
			aform.WithGroupedChoiceOptions("RGB", []aform.ChoiceFieldOption{
				{Value: "red", Label: "Rouge"},
				{Value: "green", Label: "Vert"},
				{Value: "blue", Label: "Bleu"},
			}),
		),
	)
	fmt.Println(fld.AsDiv())
}
Output:

<div><label for="id_color">Color</label><select name="color" id="id_color" required>
  <optgroup label="RGB">
    <option value="red" id="id_color_0_0">Rouge</option>
    <option value="green" id="id_color_0_1">Vert</option>
    <option value="blue" id="id_color_0_2">Bleu</option>
  </optgroup>
</select></div>

func WithHelpText

func WithHelpText(help string) FieldOption

WithHelpText returns a FieldOption that adds a help text to the Field. Help text is not HTML-escaped.

func WithLabel

func WithLabel(label string) FieldOption

WithLabel returns a FieldOption that overrides the default label of the Field.

func WithWidget

func WithWidget(widget Widget) FieldOption

WithWidget returns a FieldOption that changes the Widget of the Field.

Example (PasswordInput)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(
		aform.DefaultCharField(
			"Password",
			aform.WithWidget(aform.PasswordInput),
		),
	)
	fmt.Println(fld.AsDiv())
}
Output:

<div><label for="id_password">Password</label><input type="password" name="password" id="id_password" maxlength="256" required></div>
Example (RadioSelect)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(
		aform.DefaultChoiceField(
			"Color",
			aform.WithWidget(aform.RadioSelect),
			aform.WithChoiceOptions([]aform.ChoiceFieldOption{
				{Value: "red", Label: "Red"},
				{Value: "green", Label: "Green"},
				{Value: "blue", Label: "Blue"},
			}),
		),
	)
	fmt.Println(fld.AsDiv())
}
Output:

<div>
<fieldset><legend for="id_color">Color</legend>
<div id="id_color">
<label for="id_color_0"><input type="radio" name="color" value="red" id="id_color_0">Red</label>
<label for="id_color_1"><input type="radio" name="color" value="green" id="id_color_1">Green</label>
<label for="id_color_2"><input type="radio" name="color" value="blue" id="id_color_2">Blue</label>
</div>
</fieldset>
</div>
Example (TextArea)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	fld := aform.Must(
		aform.DefaultCharField(
			"Description",
			aform.WithWidget(aform.TextArea),
		),
	)
	fmt.Println(fld.AsDiv())
}
Output:

<div><label for="id_description">Description</label><textarea name="description" id="id_description" maxlength="256" required>
</textarea></div>

type FieldType

type FieldType string

FieldType defines the type of the fields.

type Form

type Form struct {
	// contains filtered or unexported fields
}

Form represents a form.

func New

func New(opts ...FormOption) (*Form, error)

New returns a Form.

Example (Login)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	f := aform.Must(aform.New(
		aform.WithEmailField(aform.Must(aform.DefaultEmailField("Email"))),
		aform.WithCharField(aform.Must(aform.DefaultCharField("Password", aform.WithWidget(aform.PasswordInput)))),
		aform.WithBooleanField(aform.Must(aform.DefaultBooleanField("Remember me"))),
	))
	fmt.Println(f.AsDiv())
}
Output:

<div><label for="id_email">Email</label><input type="email" name="email" id="id_email" maxlength="254" required></div>
<div><label for="id_password">Password</label><input type="password" name="password" id="id_password" maxlength="256" required></div>
<div><label for="id_remember_me">Remember me</label><input type="checkbox" name="remember_me" id="id_remember_me" required></div>
Example (NotRequiredField)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	// Create a form with two not required fields
	nicknameFld, _ := aform.NewCharField("Nickname", "", "nickname_default", 0, 0, aform.IsNotRequired())
	emailFld, _ := aform.NewEmailField("Email", "", "catchall@domain.com", 0, 0, aform.IsNotRequired())
	f, err := aform.New(
		aform.WithCharField(nicknameFld),
		aform.WithEmailField(emailFld),
	)
	if err != nil {
		panic("invalid form")
	}
	// Simulate an empty form post. Bind nil
	f.BindData(nil)
	// IsValid is true because fields are not required
	if !f.IsValid() {
		panic("form must be valid")
	}
	fmt.Println(f.CleanedData().Get("nickname"))
	fmt.Println(f.CleanedData().Get("email"))
}
Output:

nickname_default
catchall@domain.com
Example (Profile)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	f, err := aform.New(
		aform.WithCharField(aform.Must(aform.DefaultCharField("Username"))),
		aform.WithChoiceField(aform.Must(aform.DefaultChoiceField("Avatar", aform.WithChoiceOptions([]aform.ChoiceFieldOption{
			{Value: "apple", Label: "Apple"},
			{Value: "orange", Label: "Orange"},
			{Value: "strawberry", Label: "Strawberry"},
		})))),
		aform.WithChoiceField(aform.Must(aform.DefaultChoiceField(
			"Color",
			aform.WithGroupedChoiceOptions("Basic", []aform.ChoiceFieldOption{
				{Value: "red", Label: "Red"},
				{Value: "green", Label: "Green"},
				{Value: "blue", Label: "Blue"},
			}),
			aform.WithGroupedChoiceOptions("Fancy", []aform.ChoiceFieldOption{
				{Value: "orange", Label: "Orange"},
				{Value: "purple", Label: "Purple"},
				{Value: "pink", Label: "Pink"},
			}),
		)),
		),
	)
	if err != nil {
		panic("invalid form")
	}
	fmt.Println(f.AsDiv())
}
Output:

<div><label for="id_username">Username</label><input type="text" name="username" id="id_username" maxlength="256" required></div>
<div><label for="id_avatar">Avatar</label><select name="avatar" id="id_avatar" required>
  <option value="apple" id="id_avatar_0">Apple</option>
  <option value="orange" id="id_avatar_1">Orange</option>
  <option value="strawberry" id="id_avatar_2">Strawberry</option>
</select></div>
<div><label for="id_color">Color</label><select name="color" id="id_color" required>
  <optgroup label="Basic">
    <option value="red" id="id_color_0_0">Red</option>
    <option value="green" id="id_color_0_1">Green</option>
    <option value="blue" id="id_color_0_2">Blue</option>
  </optgroup>
  <optgroup label="Fancy">
    <option value="orange" id="id_color_1_0">Orange</option>
    <option value="purple" id="id_color_1_1">Purple</option>
    <option value="pink" id="id_color_1_2">Pink</option>
  </optgroup>
</select></div>
Example (YourName)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	nameForm := aform.Must(aform.New(
		aform.WithCharField(aform.Must(aform.DefaultCharField("Your name"))),
	))
	fmt.Println(nameForm.AsDiv())
}
Output:

<div><label for="id_your_name">Your name</label><input type="text" name="your_name" id="id_your_name" maxlength="256" required></div>

func (*Form) AddError

func (f *Form) AddError(field string, fieldErr error) error

AddError adds an error to the field named field. An error can be added after the form has been validated. AddError can be used in the form clean function set with SetCleanFunc to perform Form level validation. If err implements ErrorCoderTranslator, error message will be translated according to the language automatically identified by BindRequest or according to the language given to BindData.

func (*Form) AsDiv

func (f *Form) AsDiv() template.HTML

AsDiv renders the form as a list of <div> tags, with each <div> containing one field.

func (*Form) BindData

func (f *Form) BindData(data map[string][]string, langs ...string)

BindData binds data to the Form. After a first binding, following bindings are ignored. If you want to bind new data, you should create another identical Form to do it. Data is bound but not validated. Validation is done when IsValid, CleanedData or Errors are called.

func (*Form) BindRequest

func (f *Form) BindRequest(req *http.Request)

BindRequest binds req form data to the Form. After a first binding, following bindings are ignored. If you want to bind new data, you should create another identical Form to do it. Data is bound but not validated. Validation is done when IsValid, CleanedData or Errors are called. Error messages are localized according to Accept-Language header. To modify this behavior use directly BindData.

func (*Form) CleanedData

func (f *Form) CleanedData() CleanedData

CleanedData returns cleaned data validated from Form inputs. It does Form validation if it is not already done. If a field validation returns an error it doesn't appear in CleanedData.

Example (AllValid)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	f := aform.Must(aform.New(
		aform.WithEmailField(aform.Must(aform.DefaultEmailField("Email"))),
		aform.WithCharField(aform.Must(aform.DefaultCharField("Password", aform.WithWidget(aform.PasswordInput)))),
	))
	f.BindData(map[string][]string{"email": {"john.doe@gmail.com"}, "password": {"Password123"}})
	f.IsValid()
	fmt.Printf("email: \"%s\"\n", f.CleanedData().Get("email"))
	fmt.Printf("password: \"%s\"\n", f.CleanedData().Get("password"))
}
Output:

email: "john.doe@gmail.com"
password: "Password123"
Example (WithInvalidField)
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	f := aform.Must(aform.New(
		aform.WithEmailField(aform.Must(aform.DefaultEmailField("Email"))),
		aform.WithCharField(aform.Must(aform.DefaultCharField("Password", aform.WithWidget(aform.PasswordInput)))),
	))
	f.BindData(map[string][]string{"email": {"invalid email"}, "password": {"Password123"}})
	f.IsValid()
	fmt.Printf("email: \"%s\"\n", f.CleanedData().Get("email"))
	fmt.Printf("password: \"%s\"\n", f.CleanedData().Get("password"))
	fmt.Printf("email error: \"%s\"\n", f.Errors().Get("email"))
	fmt.Printf("password error: \"%s\"\n", f.Errors().Get("password"))
}
Output:

email: ""
password: "Password123"
email error: "Enter a valid email address"
password error: ""

func (*Form) Errors

func (f *Form) Errors() FormErrors

Errors returns errors happened during validation of form inputs. It does Form validation if it is not already done. If a field input is valid it doesn't appear in FormErrors.

func (*Form) FieldByName

func (f *Form) FieldByName(field string) (*Field, error)

FieldByName returns the field with the normalized name field. If there is no Field matching, an error is returned.

func (*Form) Fields

func (f *Form) Fields() []*Field

Fields returns the list of fields added to the form. First added comes first.

func (*Form) IsBound

func (f *Form) IsBound() bool

IsBound returns true if the form is already bound to data with BindRequest or BindData.

func (*Form) IsValid

func (f *Form) IsValid() bool

IsValid returns true if all the fields' validation return no error. It does Form validation if it is not already done.

func (*Form) SetCleanFunc

func (f *Form) SetCleanFunc(clean func(*Form))

SetCleanFunc sets a clean function to do validation at the form level.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	f := aform.Must(aform.New(
		aform.WithEmailField(aform.Must(aform.DefaultEmailField("email1", aform.WithLabel("Email")))),
		aform.WithEmailField(aform.Must(aform.DefaultEmailField("email2", aform.WithLabel("Email verification")))),
	))
	f.SetCleanFunc(func(form *aform.Form) {
		if !form.IsValid() {
			return
		}
		data := form.CleanedData()
		if data.Get("email1") != data.Get("email2") {
			err := fmt.Errorf("Emails must be the same")
			_ = form.AddError("email1", err)
			_ = form.AddError("email2", err)
		}
	})
	f.BindData(map[string][]string{"email1": []string{"g@gmail.com"}, "email2": []string{"h@gmail.com"}})
	// Run the form validation
	f.IsValid()
	fmt.Println(f.AsDiv())
}
Output:

<div><label for="id_email1">Email</label>
<ul class="errorlist"><li id="err_0_id_email1">Emails must be the same</li></ul>
<input type="email" name="email1" value="g@gmail.com" id="id_email1" maxlength="254" aria-describedby="err_0_id_email1" aria-invalid="true" required></div>
<div><label for="id_email2">Email verification</label>
<ul class="errorlist"><li id="err_0_id_email2">Emails must be the same</li></ul>
<input type="email" name="email2" value="h@gmail.com" id="id_email2" maxlength="254" aria-describedby="err_0_id_email2" aria-invalid="true" required></div>

type FormErrors

type FormErrors map[string][]Error

FormErrors maps a field normalized name to the list of errors after validation

func (FormErrors) Get

func (e FormErrors) Get(field string) Error

Get gets the first error associated with the given field. If there are no errors associated with the field, Get returns an empty Error with its code and message equal empty string. To access multiple errors, use the map directly.

func (FormErrors) Has

func (e FormErrors) Has(field string) bool

Has checks whether a given field has an error.

type FormOption

type FormOption func(*Form) error

FormOption describes a functional option for configuring a Form.

func DisableAutoID

func DisableAutoID() FormOption

DisableAutoID returns a FormOption that deactivates the automatic ID creation for all the fields. When auto ID is disabled fields don't have a label tag unless a field override the auto ID behaviour with Field.SetAutoID.

func WithAutoID

func WithAutoID(autoID string) FormOption

WithAutoID returns a FormOption that changes how HTML IDs are automatically built for all the fields. Correct values are either an empty string or a string containing one verb '%s'. An empty string deactivates auto ID. It's equivalent as using DisableAutoID. With a string containing one verb '%s' it's possible to customize auto ID. e.g. "id_%s"

A non-empty string without a verb '%s' is invalid.

func WithBooleanField

func WithBooleanField(fld *BooleanField) FormOption

WithBooleanField returns a FormOption that adds the BooleanField fld to the list of fields.

func WithCharField

func WithCharField(fld *CharField) FormOption

WithCharField returns a FormOption that adds the CharField fld to the list of fields.

func WithChoiceField

func WithChoiceField(fld *ChoiceField) FormOption

WithChoiceField returns a FormOption that adds the ChoiceField fld to the list of fields.

func WithEmailField

func WithEmailField(fld *EmailField) FormOption

WithEmailField returns a FormOption that adds the EmailField fld to the list of fields.

func WithErrorCSSClass

func WithErrorCSSClass(class string) FormOption

WithErrorCSSClass returns a FormOption that adds class to CSS classes when a field validation returns an error. CSS class is added to all fields that have an error after validation.

func WithLabelSuffix

func WithLabelSuffix(labelSuffix string) FormOption

WithLabelSuffix returns a FormOption that set a suffix to labels. Label suffix is added to all fields.

Example
package main

import (
	"fmt"
	"github.com/roleupjobboard/aform"
)

func main() {
	f := aform.Must(aform.New(
		aform.WithLabelSuffix(":"),
		aform.WithEmailField(aform.Must(aform.DefaultEmailField("email"))),
		aform.WithCharField(aform.Must(aform.DefaultCharField("password", aform.WithWidget(aform.PasswordInput)))),
	))
	fmt.Println(f.AsDiv())
}
Output:

<div><label for="id_email">email:</label><input type="email" name="email" id="id_email" maxlength="254" required></div>
<div><label for="id_password">password:</label><input type="password" name="password" id="id_password" maxlength="256" required></div>

func WithLocales

func WithLocales(locales []language.Tag) FormOption

WithLocales returns a FormOption that sets the list of locales used to translate error messages. Default locale is "en".

func WithMultipleChoiceField

func WithMultipleChoiceField(fld *MultipleChoiceField) FormOption

WithMultipleChoiceField returns a FormOption that adds the MultipleChoiceField fld to the list of fields.

func WithRequiredCSSClass

func WithRequiredCSSClass(class string) FormOption

WithRequiredCSSClass returns a FormOption that adds class to CSS classes when a field is required. CSS class is added to all required fields.

type FormPointerOrFieldPointer

type FormPointerOrFieldPointer interface {
	*Form | *BooleanField | *EmailField | *CharField | *ChoiceField | *MultipleChoiceField
}

FormPointerOrFieldPointer defines a union type to allow the usage of the helper function Must with forms and all fields types.

type MultipleChoiceField

type MultipleChoiceField struct {
	*Field
	// contains filtered or unexported fields
}

MultipleChoiceField is a field type that validates that the given values are contained in options listed with WithChoiceOptions or WithGroupedChoiceOptions.

func DefaultMultipleChoiceField

func DefaultMultipleChoiceField(name string, opts ...FieldOption) (*MultipleChoiceField, error)

DefaultMultipleChoiceField creates a choice field with reasonable default values. initial parameter is an empty slice. To add options use WithChoiceOptions or WithGroupedChoiceOptions.

func NewMultipleChoiceField

func NewMultipleChoiceField(name string, initials []string, opts ...FieldOption) (*MultipleChoiceField, error)

NewMultipleChoiceField creates a choice field named name. It allows multiple values to be selected. The parameter initials is the list of initial values before data bounding. To add options use WithChoiceOptions or WithGroupedChoiceOptions. The default Widget is SelectMultiple. To change it, use WithWidget or Field.SetWidget.

func (*MultipleChoiceField) Clean

func (fld *MultipleChoiceField) Clean(values []string) ([]string, []Error)

Clean returns the slice of cleaned value. values are first sanitized and finally validated. Sanitization can be customized with Field.SetSanitizeFunc. Validation can be customized with Field.SetValidateFunc.

func (*MultipleChoiceField) EmptyValue

func (fld *MultipleChoiceField) EmptyValue() []string

EmptyValue returns the MultipleChoiceField empty value. The empty value is the cleaned value returned by Clean when there is no data bound to the field. A MultipleChoiceField empty value is always an empty slice.

type SanitizationFunc

type SanitizationFunc func(string) string

SanitizationFunc defines a function to sanitize a Field.

type ValidationFunc

type ValidationFunc func(string, bool) []Error

ValidationFunc defines a function to validate a Field.

type Widget

type Widget string

Widget defines the type of the widgets.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL