Skip to content
This repository has been archived by the owner on Feb 3, 2019. It is now read-only.

bluele/gforms

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.

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

About

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

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages