gforms

package module
v0.0.0-...-133aa59 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2015 License: MIT Imports: 16 Imported by: 0

README

GForms

A flexible forms validation and rendering library for golang web development. Inspired by django-forms and wtforms.

wercker status

Overview

  • Validate HTTP request
  • Rendering form-html
  • Support parsing content-type "form-urlencoded", "json"
  • Support many widgets for form field.

Getting Started

Install

go get github.com/bluele/gforms

Examples

See examples.

Usage

Define Form
userForm := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "name",
    gforms.Validators{
      gforms.Required(),
      gforms.MaxLengthValidator(32),
    },
  ),
  gforms.NewFloatField(
    "weight",
    gforms.Validators{},
  ),
))
Validate HTTP request

Server (code):

type User struct {
  Name   string  `gforms:"name"`
  Weight float32 `gforms:"weight"`
}

func main() {
  tplText := `<form method="post">
{{range $i, $field := .Fields}}
  <label>{{$field.GetName}}: </label>{{$field.Html}}
  {{range $ei, $err := $field.Errors}}<label class="error">{{$err}}</label>{{end}}<br />
{{end}}<input type="submit">
</form>
  `
  tpl := template.Must(template.New("tpl").Parse(tplText))

  userForm := gforms.DefineForm(gforms.NewFields(
    gforms.NewTextField(
      "name",
      gforms.Validators{
        gforms.Required(),
        gforms.MaxLengthValidator(32),
      },
    ),
    gforms.NewFloatField(
      "weight",
      gforms.Validators{},
    ),
  ))

  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html")
    form := userForm(r)
    if r.Method != "POST" {
      tpl.Execute(w, form)
      return
    }
    if !form.IsValid() {
      tpl.Execute(w, form)
      return
    }
    user := User{}
    form.MapTo(&user)
    fmt.Fprintf(w, "ok: %v", user)
  })
  http.ListenAndServe(":9000", nil)
}

Client:

# show html form
$ curl -X GET localhost:9000/users
<form method="post">
  <label>name: </label><input type="text" name="name" value=""></input>
  <br />

  <label>weight: </label><input type="text" name="weight" value=""></input>
  <br />
<input type="submit">
</form>

# valid request
$ curl -X POST localhost:9000/users -d 'name=bluele&weight=71.9'
ok: {bluele 71.9}

# "name" field is required.
$ curl -X POST localhost:9000/users -d 'weight=71.9'
<form method="post">
  <label>name: </label><input type="text" name="name" value=""></input>
  <label class="error">This field is required.</label><br />

  <label>weight: </label><input type="text" name="weight" value="71.9"></input>
  <br />
<input type="submit">
</form>
Define Form by Struct Model
type User struct {
  Name   string  `gforms:"name"`
  Weight float32 `gforms:"weight"`
}

func initForm() {
  userForm := gforms.DefineModelForm(User{}, gforms.NewFields(
    // override User.name field
    gforms.NewTextField(
      "name",
      gforms.Validators{
        gforms.Required(),
        gforms.MaxLengthValidator(32),
      },
    ),
  ))
  /* equal an above defined form.
  userForm := gforms.DefineForm(gforms.NewFields(
    gforms.NewTextField(
      "name",
      gforms.Validators{
        gforms.Required(),
        gforms.MaxLengthValidator(32),
      },
    ),
    gforms.NewFloatField(
      "weight",
      gforms.Validators{},
    ),
  ))
  */
}

Render HTML

FormInstance#Html
form := userForm(r)
fmt.Println(form.Html())
/* 
# Output
<input type="text" name="name"></input>
<input type="text" name="weight"></input>
*/
FieldInstance#Html
form := userForm(r)
fmt.Println(form.GetField("name").Html())
/* 
# Output
<input type="text" name="name"></input>
*/

Parse request data

(Default) Parse *http.Request to create a new FormInstance.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  form := userForm(r)  
  ...
}
Parse net/url.Values to create a new FormInstance.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  // parse querystring values.
  form := userForm.FromUrlValues(r.URL.Query())
  ...
}

Customize Formfield attributes

customForm := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "name",
    gforms.Validators{
      gforms.Required(),
    },
    gforms.TextInputWidget(
      map[string]string{
        "class": "custom",
      },
    )),
))

form := customForm(r)
fmt.Println(form.Html())
/* 
# Output
<input type="text" name="name" value="" class="custom"></input>
*/

Custom Validation error message

userForm := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "name",
    gforms.Validators{
      gforms.Required("Custom error required message."),
      gforms.MaxLengthValidator(32, "Custom error maxlength message."),
    },
  ),
))

Support Fields

TextField

It maps value to FormInstance.CleanedData as type string.

gforms.NewTextField(
  "text",
  gforms.Validators{},
)
BooleanField

It maps value to FormInstance.CleanedData as type bool.

gforms.NewBooleanField(
  "checked",
  gforms.Validators{},
)
IntegerField

It maps value to FormInstance.CleanedData as type int.

gforms.NewIntegerField(
  "number",
  gforms.Validators{},
)
FloatField

It maps value to FormInstance.CleanedData as type float32 or float64.

gforms.NewFloatField(
  "floatNumber",
  gforms.Validators{},
)
MultipleTextField

It maps value to FormInstance.CleanedData as type []string.

gforms.NewMultipleTextField(
  "texts",
  gforms.Validators{},
)
DateTimeField

It maps value to FormInstance.CleanedData as type time.Time.

gforms.NewDateTimeField(
  "date", 
  DefaultDateTimeFormat, 
  gforms.Validators{},  
)

Support Validators

Required validator

Added an error msg to FormInstance.Errors() if the field is not provided.

gforms.Validators{
  gforms.Required(),
},
Regexp validator

Added an error msg to FormInstance.Errors() if the regexp doesn't matched a value.

gforms.Validators{
  gforms.RegexpValidator(`number-\d+`),
},
Email validator

Added an error msg to FormInstance.Errors() if a value doesn't looks like an email address.

gforms.Validators{
  gforms.EmailValidator(),
},
URL Validator

Added an error msg to FormInstance.Errors() if a value doesn't looks like an url.

gforms.Validators{
  gforms.URLValidator(),
},
MinLength Validator

Added an error msg to FormInstance.Errors() if the length of value is less than specified first argument.

gforms.Validators{
  gforms.MinLengthValidator(16),
},
MaxLength Validator

Added an error msg to FormInstance.Errors() if the length of value is greater than specified first argument.

gforms.Validators{
  gforms.MaxLengthValidator(256),
},
MinValueValidator

Added an error msg to FormInstance.Errors() if value is less than specified first argument.

gforms.Validators{
  gforms.MinValueValidator(16),
},
MaxValueValidator

Added an error msg to FormInstance.Errors() if value is greater than specified first argument.

gforms.Validators{
  gforms.MaxValueValidator(256),
},

Support Widgets

SelectWidget
Form := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "gender",
    gforms.Validators{
      gforms.Required(),
    },
    gforms.SelectWidget(
      map[string]string{
        "class": "custom",
      },
      func() gforms.SelectOptions {
        return gforms.StringSelectOptions([][]string{
          {"Men", "0"},
          {"Women", "1"},
        })
      },
    ),
  ),
))

form = Form()
fmt.Println(form.Html())
/*
# output
<select class="custom">
<option value="0">Men</option>
<option value="1">Women</option>
</select>
*/
RadioSelectWidget
Form := gforms.DefineForm(gforms.NewFields(
    gforms.NewTextField(
      "lang",
      gforms.Validators{
        gforms.Required(),
      },
      gforms.RadioSelectWidget(
        map[string]string{
          "class": "custom",
        },
        func() gforms.RadioOptions {
          return gforms.StringRadioOptions([][]string{
            {"Golang", "0", "false", "false"},
            {"Python", "1", "false", "true"},
          })
        },
      ),
    ),  
))

form = Form()
fmt.Println(form.Html())
/*
# output
<input type="radio" name="lang" value="0">Golang
<input type="radio" name="lang" value="1" disabled>Python
*/
CheckboxMultipleWidget
Form := gforms.DefineForm(gforms.NewFields(
    gforms.NewMultipleTextField(
      "lang",
      gforms.Validators{
        gforms.Required(),
      },
      gforms.CheckboxMultipleWidget(
        map[string]string{
          "class": "custom",
        },
        func() gforms.CheckboxOptions {
          return gforms.StringCheckboxOptions([][]string{
            {"Golang", "0", "false", "false"},
            {"Python", "1", "false", "true"},
          })
        },
      ),
    ),
))

form := Form()
fmt.Println(form.Html())
/*
# output
<input type="checkbox" name="lang" value="0">Golang
<input type="checkbox" name="lang" value="1" disabled>Python
*/

TODO

  • Support FileField, DateField, DateTimeField
  • Writing more godoc and unit tests.
  • Improve performance.

Author

Jun Kimura

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultDateFormat string = "2006-01-02"
View Source
var DefaultDateTimeFormat string = "2006-01-02 15:04:05"
View Source
var Template *template.Template

all templates of Field and Widget

Functions

func CheckboxMultipleWidget

func CheckboxMultipleWidget(attrs map[string]string, mk CheckboxOptionsMaker) *checkboxMultipleWidget

Generate checkbox input field: <input type="checkbox" ...>

func EmailValidator

func EmailValidator(message ...string) regexpValidator

An EmailValidator that ensures a value looks like an email address.

func MaxLengthValidator

func MaxLengthValidator(length int, message ...string) maxLengthValidator

Returns error if the length of value is greater than length argument.

func MaxValueValidator

func MaxValueValidator(value int, message ...string) maxValueValidator

func MinLengthValidator

func MinLengthValidator(length int, message ...string) minLengthValidator

Returns error if the length of value is less than length argument.

func MinValueValidator

func MinValueValidator(value int, message ...string) minValueValidator

func RadioSelectWidget

func RadioSelectWidget(attrs map[string]string, mk RadioOptionsMaker) *radioSelectWidget

Generate radio input field: <input type="radio" ...>

func RegexpValidator

func RegexpValidator(regex string, message ...string) regexpValidator

The regular expression pattern to search for the provided value. Returns error if regxp#MatchString is False.

func Required

func Required(message ...string) required

Returns error if the field is not provided.

func SelectMultipleWidget

func SelectMultipleWidget(attrs map[string]string, mk SelectOptionsMaker) *selectWidget

Generate select-multiple and options field: <select multiple><option></option></select>

func SelectWidget

func SelectWidget(attrs map[string]string, mk SelectOptionsMaker) *selectWidget

Generate select and options field: <select><option></option></select>

func URLValidator

func URLValidator(message ...string) regexpValidator

An URLValidator that ensures a value looks like an url.

Types

type BaseField

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

func (*BaseField) GetName

func (f *BaseField) GetName() string

func (*BaseField) GetValidators

func (f *BaseField) GetValidators() Validators

func (*BaseField) GetWidget

func (f *BaseField) GetWidget() Widget

type BooleanField

type BooleanField struct {
	BaseField
}

It maps value to FormInstance.CleanedData as type `bool`.

func NewBooleanField

func NewBooleanField(name string, vs Validators, ws ...Widget) *BooleanField

Create a new BooleanField with validators and widgets.

func (*BooleanField) New

func (f *BooleanField) New() FieldInterface

Create a new BooleanField instance.

type BooleanFieldInstance

type BooleanFieldInstance struct {
	FieldInstance
}

Instance for BooleanField.

func (*BooleanFieldInstance) Clean

func (f *BooleanFieldInstance) Clean(data Data) error

Get a value from request data, and clean it as type `bool`.

func (*BooleanFieldInstance) Html

func (f *BooleanFieldInstance) Html() string

Get as HTML format.

type CheckboxContext

type CheckboxContext struct {
	Field   FieldInterface
	Attrs   map[string]string
	Options checkboxOptionValues
}

type CheckboxOptions

type CheckboxOptions interface {
	Label(int) string
	Value(int) string
	Checked(int) bool
	Disabled(int) bool
	Len() int
}

type CheckboxOptionsMaker

type CheckboxOptionsMaker func() CheckboxOptions

type CleanedData

type CleanedData map[string]interface{}

cleaned data for all fields.

type Data

type Data map[string]*V

type DateTimeField

type DateTimeField struct {
	BaseField
	Format       string
	ErrorMessage string
}

It maps value to FormInstance.CleanedData as type `time.Time`.

func NewDateTimeField

func NewDateTimeField(name string, format string, vs Validators, ws ...Widget) *DateTimeField

Create a new DateTimeField with validators and widgets.

func (*DateTimeField) New

func (f *DateTimeField) New() FieldInterface

Create a new DateField instance.

type DateTimeFieldInstance

type DateTimeFieldInstance struct {
	FieldInstance
	Format       string
	ErrorMessage string
}

Instance for DateTimeField

func (*DateTimeFieldInstance) Clean

func (f *DateTimeFieldInstance) Clean(data Data) error

Get a value from request data, and clean it as type string

func (*DateTimeFieldInstance) Html

func (f *DateTimeFieldInstance) Html() string

type Errors

type Errors map[string][]string

func (Errors) Get

func (es Errors) Get(key string) []string

func (Errors) Has

func (es Errors) Has(key string) bool

type Field

type Field interface {
	New() FieldInterface
	// Get field name
	GetName() string
	GetWidget() Widget
	GetValidators() Validators
}

type FieldContext

type FieldContext struct {
	Name  string
	Type  reflect.Type
	Value reflect.Value
}

type FieldInstance

type FieldInstance struct {
	Model Field

	V *V
	FieldInterface
	// contains filtered or unexported fields
}

func (*FieldInstance) Errors

func (f *FieldInstance) Errors() []string

func (*FieldInstance) GetModel

func (f *FieldInstance) GetModel() Field

func (*FieldInstance) GetName

func (f *FieldInstance) GetName() string

func (*FieldInstance) GetV

func (f *FieldInstance) GetV() *V

func (*FieldInstance) GetWidget

func (f *FieldInstance) GetWidget() Widget

func (*FieldInstance) HasError

func (f *FieldInstance) HasError() bool

func (*FieldInstance) SetErrors

func (f *FieldInstance) SetErrors(errs []string)

func (*FieldInstance) SetInitial

func (f *FieldInstance) SetInitial(v string)

func (*FieldInstance) Validate

func (f *FieldInstance) Validate(fo *FormInstance) []string

type FieldInterface

type FieldInterface interface {
	GetModel() Field
	GetName() string
	GetV() *V
	GetWidget() Widget
	SetInitial(string)
	Clean(Data) error
	Validate(*FormInstance) []string
	Html() string

	Errors() []string
	SetErrors([]string)
	HasError() bool
	// contains filtered or unexported methods
}

type FieldInterfaces

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

type Fields

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

func NewFields

func NewFields(fields ...Field) *Fields

func (*Fields) AddField

func (fs *Fields) AddField(field Field) bool

func (*Fields) Get

func (fs *Fields) Get(name string) (Field, bool)

Get field by name.

func (*Fields) List

func (fs *Fields) List() []Field

Get ordered list for field object.

type FloatField

type FloatField struct {
	BaseField
	ErrorMessage string
}

It maps value to FormInstance.CleanedData as type `float64`.

func NewFloatField

func NewFloatField(name string, vs Validators, ws ...Widget) *FloatField

Create a new FloatField with validators and widgets.

func (*FloatField) New

func (f *FloatField) New() FieldInterface

Create a new FloatField instance.

type FloatFieldInstance

type FloatFieldInstance struct {
	FieldInstance
	ErrorMessage string
}

Instance for FloatField

func (*FloatFieldInstance) Clean

func (f *FloatFieldInstance) Clean(data Data) error

Get a value from request data, and clean it as type float64.

func (*FloatFieldInstance) Html

func (f *FloatFieldInstance) Html() string

Get as HTML format

type Form

type Form func(...*http.Request) *FormInstance

func DefineForm

func DefineForm(fs *Fields) Form

Define a new form with specified fields.

func (Form) FromRequest

func (f Form) FromRequest(r *http.Request) *FormInstance

Create a new form instance from `http.Request`.

func (Form) FromUrlValues

func (f Form) FromUrlValues(uv url.Values) *FormInstance

Create a new form instance from `url.Values`.

type FormInstance

type FormInstance struct {
	Data        Data
	CleanedData CleanedData
	ParseError  error
	// contains filtered or unexported fields
}

FormInstance made by Form.

func (*FormInstance) Errors

func (f *FormInstance) Errors() Errors

Return field errors if any fields have error after calling `FormInstance#IsValid`.

func (*FormInstance) Fields

func (f *FormInstance) Fields() []FieldInterface

Get all `FieldInstance` on `FormInstance`.

func (*FormInstance) GetField

func (f *FormInstance) GetField(name string) (FieldInterface, bool)

Get a `FieldInterface` for the given field name.

func (*FormInstance) Html

func (f *FormInstance) Html() string

Get html of each FieldInstance.

func (*FormInstance) IsValid

func (f *FormInstance) IsValid() bool

Validation request data. If any fields have errors, this method returns false.

func (*FormInstance) MapTo

func (fi *FormInstance) MapTo(model interface{})

maps cleanedData to specified model.

type IntegerField

type IntegerField struct {
	BaseField
	ErrorMessage string
}

It maps value to FormInstance.CleanedData as type `int`.

func NewIntegerField

func NewIntegerField(name string, vs Validators, ws ...Widget) *IntegerField

Create a new IntegerField with validators and widgets.

func (*IntegerField) New

func (f *IntegerField) New() FieldInterface

Create a new IntegerField instance.

type IntegerFieldInstance

type IntegerFieldInstance struct {
	FieldInstance
	ErrorMessage string
}

Instance for IntegerField

func (*IntegerFieldInstance) Clean

func (f *IntegerFieldInstance) Clean(data Data) error

Get a value from request data, and clean it as type `int`.

func (*IntegerFieldInstance) Html

func (f *IntegerFieldInstance) Html() string

Get as HTML format.

type ModelContext

type ModelContext struct {
	ModelType     reflect.Type
	FieldContexts []FieldContext
}

type ModelForm

type ModelForm func(...*http.Request) *ModelFormInstance

func DefineModelForm

func DefineModelForm(model interface{}, fs *Fields) ModelForm

Define a new form with generating fields from model's attributes and specified fields.

type ModelFormInstance

type ModelFormInstance struct {
	FormInstance
	ModelContext
}

func (*ModelFormInstance) GetModel

func (mfi *ModelFormInstance) GetModel() interface{}

type MultipleTextField

type MultipleTextField struct {
	BaseField
}

It maps value to FormInstance.CleanedData as type `[]string`.

func NewMultipleTextField

func NewMultipleTextField(name string, vs Validators, ws ...Widget) *MultipleTextField

Create a new MultipleTextField with validators and widgets.

func (*MultipleTextField) New

Create a new MultipleField instance.

type MultipleTextFieldInstance

type MultipleTextFieldInstance struct {
	FieldInstance
}

Instance for MultipleTextField.

func (*MultipleTextFieldInstance) Clean

func (f *MultipleTextFieldInstance) Clean(data Data) error

Get a value from request data, and clean it as type `[]string`.

func (*MultipleTextFieldInstance) Html

Get as HTML format.

type RadioOptions

type RadioOptions interface {
	Label(int) string
	Value(int) string
	Checked(int) bool
	Disabled(int) bool
	Len() int
}

type RadioOptionsMaker

type RadioOptionsMaker func() RadioOptions

type SelectOptions

type SelectOptions interface {
	Label(int) string
	Value(int) string
	Selected(int) bool
	Disabled(int) bool
	Len() int
}

type SelectOptionsMaker

type SelectOptionsMaker func() SelectOptions

type StringCheckboxOptions

type StringCheckboxOptions [][]string

func (StringCheckboxOptions) Checked

func (opt StringCheckboxOptions) Checked(i int) bool

func (StringCheckboxOptions) Disabled

func (opt StringCheckboxOptions) Disabled(i int) bool

func (StringCheckboxOptions) Label

func (opt StringCheckboxOptions) Label(i int) string

func (StringCheckboxOptions) Len

func (opt StringCheckboxOptions) Len() int

func (StringCheckboxOptions) Value

func (opt StringCheckboxOptions) Value(i int) string

type StringRadioOptions

type StringRadioOptions [][]string

func (StringRadioOptions) Checked

func (opt StringRadioOptions) Checked(i int) bool

func (StringRadioOptions) Disabled

func (opt StringRadioOptions) Disabled(i int) bool

func (StringRadioOptions) Label

func (opt StringRadioOptions) Label(i int) string

func (StringRadioOptions) Len

func (opt StringRadioOptions) Len() int

func (StringRadioOptions) Value

func (opt StringRadioOptions) Value(i int) string

type StringSelectOptions

type StringSelectOptions [][]string

func (StringSelectOptions) Disabled

func (opt StringSelectOptions) Disabled(i int) bool

func (StringSelectOptions) Label

func (opt StringSelectOptions) Label(i int) string

func (StringSelectOptions) Len

func (cs StringSelectOptions) Len() int

func (StringSelectOptions) Selected

func (opt StringSelectOptions) Selected(i int) bool

func (StringSelectOptions) Value

func (opt StringSelectOptions) Value(i int) string

type TextField

type TextField struct {
	BaseField
}

It maps value to FormInstance.CleanedData as type `string`.

func NewTextField

func NewTextField(name string, vs Validators, ws ...Widget) *TextField

Create a new TextField with validators and widgets.

func (*TextField) New

func (f *TextField) New() FieldInterface

Create a new TextField instance.

type TextFieldInstance

type TextFieldInstance struct {
	FieldInstance
}

Instance for TextField

func (*TextFieldInstance) Clean

func (f *TextFieldInstance) Clean(data Data) error

Get a value from request data, and clean it as type `string`.

func (*TextFieldInstance) Html

func (f *TextFieldInstance) Html() string

Get as HTML format.

type V

type V struct {
	RawStr   string
	RawValue interface{}
	// not ptr-value
	Value interface{}
	IsNil bool
	// value's kind
	Kind reflect.Kind
}

type Validator

type Validator interface {
	Name() string
	Validate(*FieldInstance, *FormInstance) error
}

type Validators

type Validators []Validator

type Widget

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

Interface for all widgets.

func BaseTextWidget

func BaseTextWidget(typ string, attrs map[string]string) Widget

func HiddenInputWidget

func HiddenInputWidget(attrs map[string]string) Widget

Generate hidden input field: <input type="hidden" ...>

func PasswordInputWidget

func PasswordInputWidget(attrs map[string]string) Widget

Generate password input field: <input type="password" ...>

func TextAreaWidget

func TextAreaWidget(attrs map[string]string) Widget

Generate text area fiele: <extarea ...>

func TextInputWidget

func TextInputWidget(attrs map[string]string) Widget

Generate text input fiele: <input type="text" ...>

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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