Created
February 16, 2013 17:20
-
-
Save kylelemons/4967786 to your computer and use it in GitHub Desktop.
Quick and dirty example of HTML forms with validation dropping data into a struct. Note that the scanf should probably be replaced with a type switch, because it likes tokenized input.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"html/template" | |
"net/url" | |
"os" | |
"regexp" | |
) | |
type FormElement interface { | |
HTML() template.HTML | |
Validate(url.Values) error | |
} | |
type TextInput struct { | |
ID string | |
Output interface{} | |
Valid *regexp.Regexp | |
} | |
func (t *TextInput) HTML() template.HTML { | |
form := fmt.Sprintf(`<input type=%q id=%q name=%q />`, "text", t.ID, t.ID) | |
return template.HTML(form) | |
} | |
func (t *TextInput) Validate(form url.Values) error { | |
val := form.Get(t.ID) | |
if !t.Valid.MatchString(val) { | |
return fmt.Errorf("%q does not match /%s/", val, t.Valid) | |
} | |
if len(val) == 0 { | |
return nil | |
} | |
if _, err := fmt.Sscan(val, t.Output); err != nil { | |
return fmt.Errorf("%q cannot be stored in %T: %s", val, t.Output, err) | |
} | |
return nil | |
} | |
type Address struct { | |
Name string | |
Street [2]string | |
City, State string | |
Zip int | |
} | |
func (a *Address) Form() map[string]FormElement { | |
return map[string]FormElement{ | |
"name": &TextInput{"nm", &a.Name, regexp.MustCompile(`\S+\s+\S+`)}, | |
"street1": &TextInput{"sn", &a.Street[0], regexp.MustCompile(`\d+.*\S+`)}, | |
"street2": &TextInput{"sx", &a.Street[1], regexp.MustCompile(`|\S+`)}, | |
"city": &TextInput{"ct", &a.City, regexp.MustCompile(`\S+`)}, | |
"state": &TextInput{"st", &a.State, regexp.MustCompile(`\S{2}`)}, | |
"zip": &TextInput{"zp", &a.Zip, regexp.MustCompile(`\d{5}(-\d{4})?`)}, | |
} | |
} | |
func main() { | |
var a Address | |
form := a.Form() | |
tpl := template.Must(template.New("").Parse("{{.name.HTML}}\n{{.street1.HTML}}\n...\n\n")) | |
tpl.Execute(os.Stdout, form) | |
reply := url.Values{ | |
"nm": {"Zaphod Beeblebrox"}, | |
"sn": {"42 Heart of Gold"}, | |
"ct": {"Betelgeuse Central"}, | |
"st": {"BG"}, | |
"zp": {"42069"}, | |
} | |
for id, f := range form { | |
if err := f.Validate(reply); err != nil { | |
fmt.Printf("%q - %s\n", id, err) | |
} | |
} | |
fmt.Printf("%#v", a) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment