GithubHelp home page GithubHelp logo

bluele / gforms Goto Github PK

View Code? Open in Web Editor NEW
126.0 12.0 20.0 94 KB

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

License: MIT License

Go 100.00%

gforms's Introduction

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

gforms's People

Contributors

bluele avatar gavbaa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gforms's Issues

Define input type.

Hey guys, good thing you got going here, really like it. I have a question about defining input types, such as text, email, tel and so on.

If I use InputTextWidget, that will give me two type attributes, which is not good. Is there a proper way of setting type attributes, or it's built in as text.

P.S. I have a feeling that I'm missing something.

MapTo should support structs with pointers

MapTo currently does not populate fields in structs if those fields are pointers. This makes the library harder to use with existing domain objects.

    type Domain struct {
        Name *string
        Expiration *time.Time
    }

I've created a PR ( #9 ) to address this for any level of pointers.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.