formulate

package module
v1.6.0 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2024 License: MIT Imports: 16 Imported by: 4

README

formulate Godoc

a HTML form builder and HTTP request to struct parser.

Example (Formulate)
type Address struct {
	HouseName       string `help:"You can leave this blank."`
	AddressLine1    string
	AddressLine2    string
	Postcode        string
	TelephoneNumber Tel
	CountryCode     string `pattern:"[A-Za-z]{3}" validators:"countryCode"`
}

buildEncoder := func(r *http.Request, w io.Writer) *HTMLEncoder {
	enc := NewEncoder(w, r, nil)
	enc.SetFormat(true)

	return enc
}

buildDecoder := func(r *http.Request, values url.Values) *HTTPDecoder {
	dec := NewDecoder(values)
	dec.SetValueOnValidationError(true)
	dec.AddValidators(countryCodeValidator{})

	return dec
}

handler := func(w http.ResponseWriter, r *http.Request) {
	var addressForm Address

	encodedForm, save, err := Formulate(r, &addressForm, buildEncoder, buildDecoder)

	if err == nil && save {
		// save the form here
		http.Redirect(w, r, "/", http.StatusFound)
	} else if err != nil {
		http.Error(w, "Bad Form", http.StatusInternalServerError)
		return
	}

	w.Header().Add("Content-Type", "text/html")
	_, _ = w.Write(encodedForm)
}

// example validator
type countryCodeValidator struct{}

func (c countryCodeValidator) Validate(value interface{}) (ok bool, message string) {
   switch a := value.(type) {
   case string:
	   if len(a) == 3 && strings.ToUpper(a) == a {
		   return true, ""
	   }
	   return false, "Country codes must be 3 letters and uppercase"
   default:
	   return false, "invalid type"
   }
}

func (c countryCodeValidator) TagName() string {
	return "countryCode"
}
Example (Encoder)
type Address struct {
    HouseName       string `help:"You can leave this blank."`
    AddressLine1    string
    AddressLine2    string
    Postcode        string
    TelephoneNumber Tel
    CountryCode     string `pattern:"[A-Za-z]{3}"`
}

buf := new(bytes.Buffer)

address := Address{
    AddressLine1: "Fake Street",
}

encoder := NewEncoder(buf, nil, nil)
encoder.SetFormat(true)

if err := encoder.Encode(&address); err != nil {
    panic(err)
}

fmt.Println(buf.String())

Output:

<div>
  <fieldset>
    <div>
      <label for="HouseName">
        House Name
      </label>
      <div>
        <input type="text" name="HouseName" id="HouseName" value=""/>
        <div>You can leave this blank.</div>
      </div>
    </div>
    <div>
      <label for="AddressLine1">
        Address Line 1
      </label>
      <div>
        <input type="text" name="AddressLine1" id="AddressLine1" value="Fake Street"/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="AddressLine2">
        Address Line 2
      </label>
      <div>
        <input type="text" name="AddressLine2" id="AddressLine2" value=""/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="Postcode">
        Postcode
      </label>
      <div>
        <input type="text" name="Postcode" id="Postcode" value=""/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="TelephoneNumber">
        Telephone Number
      </label>
      <div>
        <input type="tel" name="TelephoneNumber" id="TelephoneNumber" value=""/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="CountryCode">
        Country Code
      </label>
      <div>
        <input type="text" name="CountryCode" id="CountryCode" value="" pattern="[A-Za-z]{3}"/>
        <div></div>
      </div>
    </div>
  </fieldset>
</div>
Example (Decoder)
type Address struct {
    HouseName       string `help:"You can leave this blank."`
    AddressLine1    string
    AddressLine2    string
    Postcode        string
    TelephoneNumber Tel
    CountryCode     string `pattern:"[A-Za-z]{3}"`
}

// formValues - usually these would come from *http.Request.Form!
formValues := url.Values{
    "HouseName":       {"1 Example Road"},
    "AddressLine1":    {"Fake Town"},
    "AddressLine2":    {"Fake City"},
    "Postcode":        {"Postcode"},
    "TelephoneNumber": {"012345678910"},
    "CountryCode":     {"GBR"},
}

var address Address

decoder := NewDecoder(formValues)

if err := decoder.Decode(&address); err != nil {
    panic(err)
}

fmt.Printf("House Name: %s\n", address.HouseName)
fmt.Printf("Line 1: %s\n", address.AddressLine1)
fmt.Printf("Line 2: %s\n", address.AddressLine2)
fmt.Printf("Postcode: %s\n", address.Postcode)
fmt.Printf("Telephone: %s\n", address.TelephoneNumber)
fmt.Printf("CountryCode: %s\n", address.CountryCode)

Output:

House Name: 1 Example Road
Line 1: Fake Town
Line 2: Fake City
Postcode: Postcode
Telephone: 012345678910
CountryCode: GBR

Documentation

Overview

Package formulate is a set of tools for building HTML forms from structs, and parsing HTTP form values back into structs.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrFormFailedValidation = errors.New("formulate: form failed validation")

ErrFormFailedValidation is returned if any form fields did not pass validation.

View Source
var (
	// ErrInvalidCSRFToken indicates that the csrf middleware has not been loaded in the handler chain.
	ErrInvalidCSRFToken = errors.New("formulate: invalid CSRF token")
)

Functions

func AppendClass

func AppendClass(n *html.Node, classes ...string)

AppendClass adds a class to a HTML node.

func BuildBoolField added in v1.0.1

func BuildBoolField(v reflect.Value, key string) *html.Node

func BuildField added in v1.0.2

func BuildField(v reflect.Value, key string, field StructField, parent *html.Node, decorator Decorator, showConditions ShowConditions) error

func BuildHelpText added in v1.0.2

func BuildHelpText(parent *html.Node, field StructField, decorator Decorator)

func BuildLabel added in v1.0.2

func BuildLabel(label string, parent *html.Node, field StructField, decorator Decorator)

func BuildNumberField added in v1.0.1

func BuildNumberField(v reflect.Value, key string, field StructField) *html.Node

func BuildRadioButtons added in v1.0.1

func BuildRadioButtons(r RadioList, key string, field StructField, decorator Decorator) *html.Node

func BuildSelectField added in v1.0.1

func BuildSelectField(s Select, key string) *html.Node

func BuildStringField added in v1.0.1

func BuildStringField(v reflect.Value, key string, field StructField) *html.Node

func BuildTimeField added in v1.0.1

func BuildTimeField(t time.Time, key string, field StructField) *html.Node

func BuildValidationText added in v1.2.0

func BuildValidationText(parent *html.Node, field StructField, decorator Decorator)

func FormElementName added in v1.5.0

func FormElementName(key string) string

FormElementName returns the name of the form element within the form, removing the package path and base struct name.

func Formulate added in v1.2.0

func Formulate(r *http.Request, data interface{}, encoderBuilder HTMLEncoderBuilder, decoderBuilder HTTPDecoderBuilder) (encodedForm template.HTML, passedValidation bool, err error)

Formulate is an all-in-one method for handling form encoding and decoding, including validation errors. This expects the form to be POST-ed to the same endpoint as the form is displayed on. If you require a custom implementation of the form handling (including on separate endpoints), this can be done with the HTMLEncoder.Encode and HTTPDecoder.Decode methods. The Formulate method overrides any ValidationStore already set and uses a MemoryValidationStore instead.

Example
type Address struct {
	HouseName       string `help:"You can leave this blank."`
	AddressLine1    string
	AddressLine2    string
	Postcode        string
	TelephoneNumber Tel
	CountryCode     string `pattern:"[A-Za-z]{3}" validators:"countryCode"`
}

buildEncoder := func(r *http.Request, w io.Writer) *HTMLEncoder {
	enc := NewEncoder(w, r, nil)
	enc.SetFormat(true)

	return enc
}

buildDecoder := func(r *http.Request, values url.Values) *HTTPDecoder {
	dec := NewDecoder(values)
	dec.SetValueOnValidationError(true)
	dec.AddValidators(countryCodeValidator{})

	return dec
}

handler := func(w http.ResponseWriter, r *http.Request) {
	var addressForm Address

	encodedForm, save, err := Formulate(r, &addressForm, buildEncoder, buildDecoder)

	if err == nil && save {
		// save the form here
		http.Redirect(w, r, "/", http.StatusFound)
	} else if err != nil {
		http.Error(w, "Bad Form", http.StatusInternalServerError)
		return
	}

	w.Header().Add("Content-Type", "text/html")
	_, _ = w.Write([]byte(encodedForm))
}

// for example purposes only.
srv := httptest.NewServer(http.HandlerFunc(handler))
defer srv.Close()

resp, err := http.Get(srv.URL)

if err != nil {
	panic(err)
}

defer resp.Body.Close()

b, _ := ioutil.ReadAll(resp.Body)

fmt.Println(string(b))
Output:

<div>
  <fieldset>
    <div>
      <label for="HouseName">
        House Name
      </label>
      <div>
        <input type="text" name="HouseName" id="HouseName" value=""/>
        <div>
          You can leave this blank.
        </div>
      </div>
    </div>
    <div>
      <label for="AddressLine1">
        Address Line 1
      </label>
      <div>
        <input type="text" name="AddressLine1" id="AddressLine1" value=""/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="AddressLine2">
        Address Line 2
      </label>
      <div>
        <input type="text" name="AddressLine2" id="AddressLine2" value=""/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="Postcode">
        Postcode
      </label>
      <div>
        <input type="text" name="Postcode" id="Postcode" value=""/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="TelephoneNumber">
        Telephone Number
      </label>
      <div>
        <input type="tel" name="TelephoneNumber" id="TelephoneNumber" value=""/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="CountryCode">
        Country Code
      </label>
      <div>
        <input type="text" name="CountryCode" id="CountryCode" value="" pattern="[A-Za-z]{3}"/>
        <div></div>
      </div>
    </div>
  </fieldset>
</div>

func HasAttribute

func HasAttribute(n *html.Node, attr string) bool

HasAttribute returns true if n has the attribute named attr.

func OptGroup added in v1.0.3

func OptGroup(name string) *string

func PopFormValue added in v1.5.0

func PopFormValue(form url.Values, key string) (string, bool)

PopFormValue takes a value from the form and removes it so that it is not parsed again.

func RenderHTMLToNode added in v1.4.0

func RenderHTMLToNode(data template.HTML, parent *html.Node) error

RenderHTMLToNode renders a html string into a parent *html.Node. The parent node is emptied before the data is rendered into it.

Types

type BoolNumber

type BoolNumber int

BoolNumber represents an int (0 or 1) which should actually be rendered as a checkbox. It is provided here as a convenience, as many structures use 0 or 1 to represent booleans values.

func (BoolNumber) Bool

func (bn BoolNumber) Bool() bool

Bool returns true if the underlying value is 1.

func (BoolNumber) DecodeFormValue

func (bn BoolNumber) DecodeFormValue(form url.Values, name string, _ []string) (reflect.Value, error)

DecodeFormValue implements the CustomDecoder interface.

type Condition

type Condition bool

Condition are optional booleans for Options.

func NewCondition

func NewCondition(b bool) *Condition

NewCondition creates a new condition based on a bool value.

type CustomDecoder

type CustomDecoder interface {
	// DecodeFormValue is passed the whole form values, the name of the element that it is decoding,
	// and the values for that specific element. It must return a reflect.Value of equal type to the
	// type which is implementing the CustomDecoder interface. If err != nil, the error will propagate
	// back through to the Decode() call.
	//
	// By default, primitive types supported by formulate will remove the values from the form as the form is decoded.
	// CustomDecoders may replicate this behaviour if needed, but formulate will not do it automatically.
	// See PopFormValue and FormElementName for more information.
	DecodeFormValue(form url.Values, name string, values []string) (reflect.Value, error)
}

CustomDecoder allows for custom decoding behavior to be specified for an element. If a type implements the CustomDecoder interface, DecodeFormValue is called in place of any other decoding behavior.

type CustomEncoder

type CustomEncoder interface {
	// BuildFormElement is passed the key of the form element as computed by formulate,
	// the parent node of the element, the field of the struct
	// that is currently being rendered, and the form's decorator.
	// Note that the built element must be appended to the parent or it will not be shown in the form!
	// Errors returned from BuildFormElement propagate back through to the formulate.Encoder.Encode call.
	BuildFormElement(key string, parent *html.Node, field StructField, decorator Decorator) error
}

CustomEncoder allows for custom rendering behavior of a type to be implemented. If a type implements the CustomEncoder interface, BuildFormElement is called in place of any other formulate rendering behavior for inputs. The label and help text of the element will still be rendered within the row as normal.

type Decorator

type Decorator interface {
	// RootNode decorates the root <div> of the returned HTML.
	RootNode(n *html.Node)
	// Fieldset decorates each <fieldset>. Fieldsets are created for each
	// non-anonymous struct within the encoded data structure.
	Fieldset(n *html.Node, field StructField)
	// Row decorates the parent of each label, input and help text, for each field within the encoded data structure.
	Row(n *html.Node, field StructField)
	// FieldWrapper decorates the div which wraps the input and help text within a form
	FieldWrapper(n *html.Node, field StructField)
	// Label decorates the <label> for the form element
	Label(n *html.Node, field StructField)
	// HelpText decorates the text which is displayed below each form element.
	// The HelpText is generated from the "help" struct tag.
	HelpText(n *html.Node, field StructField)
	// TextField decorates an <input type="text">
	TextField(n *html.Node, field StructField)
	// NumberField decorates an <input type="number"> or equivalent (e.g. Tel)
	NumberField(n *html.Node, field StructField)
	// CheckboxField decorates an <input type="checkbox">, displayed for boolean values.
	CheckboxField(n *html.Node, field StructField)
	// TextareaField decorates a <textarea> tag.
	TextareaField(n *html.Node, field StructField)
	// TimeField decorates an <input type="datetime-local"> used to represent time values.
	TimeField(n *html.Node, field StructField)
	// SelectField decorates a <select> dropdown
	SelectField(n *html.Node, field StructField)
	// RadioButton decorates an individual <input type="radio">
	RadioButton(n *html.Node, field StructField)
	// ValidationText decorates the text which is displayed below each form element when there is a validation error.
	ValidationText(n *html.Node, field StructField)
}

Decorator is used to customise node elements that are built by the HTMLEncoder. Custom decorators can be passed into the HTMLEncoder. If no decorator is specified, a nil decorator is used. This applies no decoration to the output HTML.

type Email

type Email string

Email represents an <input type="email">

type FormAwareValidator added in v1.2.0

type FormAwareValidator interface {
	Validator

	SetForm(form url.Values)
}

FormAwareValidator is a Validator that is aware of the full form that was posted. This can be used for validation that requires knowledge of other form values.

type HTMLEncoder

type HTMLEncoder struct {
	ShowConditions
	// contains filtered or unexported fields
}

HTMLEncoder is used to generate an HTML form from a given struct.

func NewEncoder

func NewEncoder(w io.Writer, r *http.Request, decorator Decorator) *HTMLEncoder

NewEncoder returns a HTMLEncoder which outputs to w. A Decorator can be passed to NewEncoder, which will then be used to style the outputted HTML. If nil is passed in, no decorator is used, and a bare-bones HTML form will be returned.

Example
type Address struct {
	HouseName       string `help:"You can leave this blank."`
	AddressLine1    string
	AddressLine2    string
	Postcode        string
	TelephoneNumber Tel
	CountryCode     string `pattern:"[A-Za-z]{3}"`
}

buf := new(bytes.Buffer)

address := Address{
	AddressLine1: "Fake Street",
}

encoder := NewEncoder(buf, nil, nil)
encoder.SetFormat(true)

if err := encoder.Encode(&address); err != nil {
	panic(err)
}

fmt.Println(buf.String())
Output:

<div>
  <fieldset>
    <div>
      <label for="HouseName">
        House Name
      </label>
      <div>
        <input type="text" name="HouseName" id="HouseName" value=""/>
        <div>
          You can leave this blank.
        </div>
      </div>
    </div>
    <div>
      <label for="AddressLine1">
        Address Line 1
      </label>
      <div>
        <input type="text" name="AddressLine1" id="AddressLine1" value="Fake Street"/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="AddressLine2">
        Address Line 2
      </label>
      <div>
        <input type="text" name="AddressLine2" id="AddressLine2" value=""/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="Postcode">
        Postcode
      </label>
      <div>
        <input type="text" name="Postcode" id="Postcode" value=""/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="TelephoneNumber">
        Telephone Number
      </label>
      <div>
        <input type="tel" name="TelephoneNumber" id="TelephoneNumber" value=""/>
        <div></div>
      </div>
    </div>
    <div>
      <label for="CountryCode">
        Country Code
      </label>
      <div>
        <input type="text" name="CountryCode" id="CountryCode" value="" pattern="[A-Za-z]{3}"/>
        <div></div>
      </div>
    </div>
  </fieldset>
</div>

func (*HTMLEncoder) Encode

func (h *HTMLEncoder) Encode(i interface{}) (err error)

Encode takes a struct (or struct pointer) and produces an HTML form from all elements in the struct. The encoder deals with most simple types and structs, but more complex types (maps, slices, arrays) will render as a JSON blob in a <textarea>.

The rendering behavior of any element can be replaced by implementing the CustomEncoder interface. Encode calls will clear the ValidationStore, regardless of error state.

func (*HTMLEncoder) SetCSRFProtection added in v1.4.0

func (h *HTMLEncoder) SetCSRFProtection(enabled bool)

SetCSRFProtection can be used to enable CSRF protection. The gorilla/csrf middleware must be loaded, or the Encode call will fail. SetCSRFProtection must also be enabled on the HTTPDecoder. Validation of CSRF tokens is handled by the gorilla/csrf middleware, not formulate.

func (*HTMLEncoder) SetFormat

func (h *HTMLEncoder) SetFormat(b bool)

SetFormat tells the HTMLEncoder to output formatted HTML. Formatting is provided by the https://github.com/yosssi/gohtml package.

func (*HTMLEncoder) SetValidationStore added in v1.2.0

func (h *HTMLEncoder) SetValidationStore(v ValidationStore)

SetValidationStore can be used to tell the HTMLEncoder about previous validation errors.

type HTMLEncoderBuilder added in v1.2.0

type HTMLEncoderBuilder func(r *http.Request, w io.Writer) *HTMLEncoder

HTMLEncoderBuilder is a function that builds a HTMLEncoder given an io.Writer as the output. When used with the Formulate method, this allows for custom building of the encoder (including ShowConditions etc).

type HTTPDecoder

type HTTPDecoder struct {
	ShowConditions
	// contains filtered or unexported fields
}

HTTPDecoder takes a set of url values and decodes them.

func NewDecoder

func NewDecoder(form url.Values) *HTTPDecoder

NewDecoder creates a new HTTPDecoder.

Example
type Address struct {
	HouseName       string `help:"You can leave this blank."`
	AddressLine1    string
	AddressLine2    string
	Postcode        string
	TelephoneNumber Tel
	CountryCode     string `pattern:"[A-Za-z]{3}" validators:"countryCode"`

	EmptyStruct struct {
		Foo string `show:"-"`
	}
}

// formValues - usually these would come from *http.Request.Form!
formValues := url.Values{
	"HouseName":       {"1 Example Road"},
	"AddressLine1":    {"Fake Town"},
	"AddressLine2":    {"Fake City"},
	"Postcode":        {"Postcode"},
	"TelephoneNumber": {"012345678910"},
	"CountryCode":     {"GBR"},
}

var address Address

decoder := NewDecoder(formValues)
decoder.AddValidators(countryCodeValidator{})
decoder.SetValueOnValidationError(true)

if err := decoder.Decode(&address); err != nil {
	panic(err)
}

fmt.Printf("House Name: %s\n", address.HouseName)
fmt.Printf("Line 1: %s\n", address.AddressLine1)
fmt.Printf("Line 2: %s\n", address.AddressLine2)
fmt.Printf("Postcode: %s\n", address.Postcode)
fmt.Printf("Telephone: %s\n", address.TelephoneNumber)
fmt.Printf("CountryCode: %s\n", address.CountryCode)
Output:

House Name: 1 Example Road
Line 1: Fake Town
Line 2: Fake City
Postcode: Postcode
Telephone: 012345678910
CountryCode: GBR

func (*HTTPDecoder) AddValidators added in v1.2.0

func (h *HTTPDecoder) AddValidators(validators ...Validator)

AddValidators registers Validators to the decoder.

func (*HTTPDecoder) Decode

func (h *HTTPDecoder) Decode(data interface{}) error

Decode the given values into a provided interface{}. Note that the underlying value must be a pointer.

func (*HTTPDecoder) SetValidationStore added in v1.3.0

func (h *HTTPDecoder) SetValidationStore(v ValidationStore)

func (*HTTPDecoder) SetValueOnValidationError added in v1.2.0

func (h *HTTPDecoder) SetValueOnValidationError(b bool)

SetValueOnValidationError indicates whether a form value should be set in the form if there was a validation error on that value.

type HTTPDecoderBuilder added in v1.2.0

type HTTPDecoderBuilder func(r *http.Request, values url.Values) *HTTPDecoder

HTTPDecoderBuilder is a function that builds a HTTPDecoder given the form as the input. When used with the Formulate method, this allows for custom building of the decoder (including ShowConditions, Validators etc).

type MemoryValidationStore added in v1.3.0

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

func NewMemoryValidationStore added in v1.3.0

func NewMemoryValidationStore() *MemoryValidationStore

func (*MemoryValidationStore) AddValidationError added in v1.3.0

func (m *MemoryValidationStore) AddValidationError(field string, validationError ValidationError) error

func (*MemoryValidationStore) ClearValidationErrors added in v1.3.0

func (m *MemoryValidationStore) ClearValidationErrors() error

func (*MemoryValidationStore) GetFormValue added in v1.3.0

func (m *MemoryValidationStore) GetFormValue(out interface{}) error

func (*MemoryValidationStore) GetValidationErrors added in v1.3.0

func (m *MemoryValidationStore) GetValidationErrors(field string) ([]ValidationError, error)

func (*MemoryValidationStore) SetFormValue added in v1.3.0

func (m *MemoryValidationStore) SetFormValue(val interface{}) error

type Option

type Option struct {
	Value interface{}
	Label string
	Group *string

	Disabled bool
	Checked  *Condition
	Attr     []html.Attribute
}

Option represents an option in Select inputs and Radio inputs.

type Password

type Password string

Password represents an <input type="password">

type RadioList

type RadioList interface {
	CustomDecoder

	RadioOptions() []Option
}

RadioList represents a list of <input type="radio">. Radio lists must implement their own decoder.

type Raw

type Raw []byte

Raw is byte data which should be rendered as a string inside a textarea.

func (Raw) BuildFormElement

func (r Raw) BuildFormElement(key string, parent *html.Node, field StructField, decorator Decorator) error

BuildFormElement implements the CustomEncoder interface.

type Select

type Select interface {
	// SelectMultiple indicates whether multiple options can be selected at once.
	SelectMultiple() bool

	// SelectOptions are the available options
	SelectOptions() []Option
}

Select represents a HTML <select> element.

type ShowConditionFunc

type ShowConditionFunc func(field StructField) bool

ShowConditionFunc is a function which determines whether to show a form element. See: HTMLEncoder.AddShowCondition

type ShowConditions added in v1.6.0

type ShowConditions map[string][]ShowConditionFunc

func (ShowConditions) AddGlobalShowCondition added in v1.6.0

func (s ShowConditions) AddGlobalShowCondition(fn ShowConditionFunc)

AddGlobalShowCondition adds a ShowConditionFunc to be called on all StructFields.

func (ShowConditions) AddShowCondition added in v1.6.0

func (s ShowConditions) AddShowCondition(key string, fn ShowConditionFunc)

AddShowCondition allows you to determine visibility of certain form elements. For example, given the following struct:

type Example struct {
  Name string
  SecretOption bool `show:"adminOnly"`
}

If you wanted to make the SecretOption field only show to admins, you would call AddShowCondition as follows:

AddShowCondition("adminOnly", func(field StructField) bool {
   // some code that determines if we are 'admin'
})

You can add multiple ShowConditions for the same key.

It is also possible to add ShowConditionFuncs to be used on every StructField. See AddGlobalShowCondition.

Note: ShowConditions should be added to both the Encoder and Decoder.

type StructField

type StructField struct {
	reflect.StructField

	// ValidationErrors are the errors present for the StructField. They are only set on an encode.
	ValidationErrors []ValidationError
}

StructField is a wrapper around the reflect.StructField type. The rendering behavior of form elements is controlled by Struct Tags. The following tags are currently available:

  • name (e.g. name:"Phone Number") - this overwrites the name used in the label. This value can be left empty.
  • help (e.g. help:"Enter your phone number, including area code") - this text is displayed alongside the input field as a prompt.
  • show (e.g. show:"adminOnly") - controls visibility of elements. See HTMLEncoder.AddShowCondition for more details. If "contents" is used, the field is shown and the parent fieldset (if any) will be omitted. If "fieldset" is used, anonymous structs will be built as fieldsets too, if their name is also set.
  • type (e.g. type:"tel", type:"hidden") - sets the HTML input "type" attribute. type:"hidden" will be rendered without labels and help text.
  • elem (elem:"textarea") - used to specify that a text input should use a <textarea> rather than an input field.
  • min (e.g. min:"0") - minimum value for number inputs, minimum length for text inputs
  • max (e.g. max:"10") - maximum value for number inputs, maximum length for text inputs
  • step (e.g. step:"0.1") - step size for number inputs
  • pattern (e.g. pattern:"[a-z]+" - regex pattern for text inputs
  • required (true/false) - adds the required attribute to the element.
  • placeholder (e.g. placeholder:"phone number") - indicates a placeholder for the element.
  • validators (e.g. "email,notempty") - which registered Validators to use.

These can all be used in combination with one another in a struct field. A full example of the above types is:

type Address struct {
    HouseNumber          int `min:"0" help:"Please enter your house number" name:"House Number (if any)"
    AddressLine1         string
    DeliveryInstructions string `elem:"textarea"`
    CountryCode          string `pattern:"[A-Za-z]{3}"`
}

func (StructField) BuildFieldset

func (sf StructField) BuildFieldset() bool

BuildFieldset determines whether a given struct should be inside its own fieldset. Use the Struct Tag show:"contents" to indicate that a fieldset should not be built for this struct. Use show:"fieldset" to indicate that anonymous structs should be built in a fieldset.

func (StructField) Elem

func (sf StructField) Elem() string

Elem returns the element to be used. Currently, the only supported value is <textarea>. <input> will be used if not specified.

func (StructField) GetHelpText

func (sf StructField) GetHelpText() string

GetHelpText returns the help text for the field.

func (StructField) GetName

func (sf StructField) GetName() string

GetName returns the name of the StructField, taking into account tag name overrides.

func (StructField) HasMax

func (sf StructField) HasMax() bool

HasMax determines if a StructField has a maximum value

func (StructField) HasMin

func (sf StructField) HasMin() bool

HasMin determines if a StructField has a minimum value

func (StructField) HasStep

func (sf StructField) HasStep() bool

HasStep determines if a StructField has a step value

func (StructField) Hidden

func (sf StructField) Hidden(showConditions ShowConditions) bool

Hidden determines if a StructField is hidden based on the showConditions. If multiple show conditions are specified, they must all pass for the field to be visible.

func (StructField) InputType

func (sf StructField) InputType(original string) string

InputType returns the HTML <input> element type attribute

func (StructField) IsExported added in v1.3.7

func (sf StructField) IsExported() bool

func (StructField) Max

func (sf StructField) Max() string

Max is the maximum value of the StructField

func (StructField) Min

func (sf StructField) Min() string

Min is the minimum value of the StructField

func (StructField) Pattern

func (sf StructField) Pattern() string

Pattern is the regex for the input field.

func (StructField) Placeholder added in v1.0.2

func (sf StructField) Placeholder() string

Placeholder defines the placeholder attribute for the input field

func (StructField) Required added in v1.0.2

func (sf StructField) Required() bool

Required indicates that an input field must be filled in.

func (StructField) Step

func (sf StructField) Step() string

Step value of the StructField

func (StructField) Validators added in v1.2.0

func (sf StructField) Validators() []ValidatorKey

Validators are the TagNames of the registered Validators. Multiple Validators may be specified, separated by a comma.

type Tel

type Tel string

Tel represents an <input type="tel">

type URL

type URL string

URL represents an <input type="url">

type ValidationError added in v1.2.0

type ValidationError struct {
	// Error is the error message returned by the Validator.Validate method.
	Error string

	// Value is the value which failed validation.
	Value interface{}
}

ValidationError is an error generated by the validation process. Each field may have multiple validation errors.

type ValidationStore added in v1.2.0

type ValidationStore interface {
	// GetValidationErrors returns the errors for a given field.
	GetValidationErrors(field string) ([]ValidationError, error)

	// AddValidationError adds a validation error to the store
	AddValidationError(field string, validationError ValidationError) error

	// ClearValidationErrors removes all validation errors from the store
	ClearValidationErrors() error

	// SetFormValue saves the posted form value. It is only called if there are validation errors.
	SetFormValue(val interface{}) error

	// GetFormValue unmarshals the posted form value into the out interface.
	GetFormValue(out interface{}) error
}

ValidationStore is a data store for the validation errors

type Validator added in v1.2.0

type Validator interface {
	// Validate a given value. If the value passes your validation, return true, and no message.
	// If the value fails validation, return false and a validation message.
	Validate(value interface{}) (ok bool, message string)
	// TagName is the name of the validator. This must match the tag name used in the struct tag on the form field.
	// For example for a field with a tag: `validators:"email"`, the TagName returned here must be "email".
	TagName() string
}

Validator is an interface that allows individual form fields to be validated as part of the Decode phase of a formulate form. Validators may be reused for multiple form fields.

type ValidatorKey added in v1.2.0

type ValidatorKey string

ValidatorKey is used to match the Validator's TagName against that on a StructField.

Directories

Path Synopsis
stores

Jump to

Keyboard shortcuts

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