form

package module
v2.0.1+incompatible Latest Latest
Warning

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

Go to latest
Published: Jun 5, 2015 License: MIT Imports: 15 Imported by: 2

README

CJToolkit Form

Automated Form Rendering and Validation Library for Google Go.

  • Integration with 'github.com/cjtoolkit/i18n'.
    • So it can speak your lingo.
  • Dual layer rendering system.
    • So it can easily be adapted to any CSS framework, such as Bootstrap or Foundation.
    • Currently support Bootstrap and Foundation out of the box.
    • First layer is fixed.
    • Second layer is user definable.
      • So you can use your own CSS framework.
  • Relies on Struct Pointers with only one methods
    • So you can pretty much do anything you desire.
      • Defining your own rules (see below).
      • i18n integration.
      • Database integration either with or without ORM, Your choice.
    • No Struct tags are needed, not that there anything wrong with them, just not suitable for forms, it's just too complex for struct tags.
    • No Reflection, No Magic, just straight up pointers.
    • See example below, than have a look at document, it will help you understand the system.

Documentation can be found at.

Installation

#!/bin/zsh

go get github.com/cjtoolkit/form

# Optional checkout to stable version, must be in $GOPATH/src/github.com/cjtoolkit/form
git checkout v2.0.1

Example

Actual Application
package main

import (
	"fmt"
	"io"
	"mime/multipart"
	"net/http"

	"github.com/cjtoolkit/form"
	_ "github.com/cjtoolkit/form/lang/enGB"
)

type TestForm struct {
	Text string
	File *multipart.FileHeader
}

func (t *TestForm) CJForm(f *form.Fields) {
	// Text
	func() {
		f := f.Init(&t.Text, "Text", form.InputText)
		html := f.HTML()
		html.Before = "<h1>File Test</h1>"
	}()

	// File
	func() {
		f := f.Init(&t.File, "File", form.InputFile)
		file := f.File()
		file.Size = 10 * 1024 * 1024
		file.Accept = []string{"image/jpeg", "image/png"}
	}()
}

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		f := &TestForm{}
		v := form.New(req, nil, "en-GB")
		get := func() {
			res.Header().Set("Content-Type", "text/html")

			fmt.Fprint(res, `<form action="/" method="post" enctype="multipart/form-data">
`)
			v.Render(res, f)

			fmt.Fprint(res, `<input type="submit" name="submit" value="Submit">
</form>`)
		}

		switch req.Method {
		case "GET":
			get()
		case "POST":
			req.ParseMultipartForm(10 * 1024 * 1024)
			if !v.MustValidate(f) && f.File == nil {
				get()
				return
			}

			file, _ := f.File.Open()
			io.Copy(res, file)
		}
	})

	http.ListenAndServe(":8080", mux)
}
Defining Custom Rules
func (e *Example) CJForm(f *form.Fields) {
	// Text
	func() {
		f := f.Init(&e.Text, "Text", form.InputText)

		f.Custom(func(e *error, w *string) {
			*e = fmt.Errorf("Error message here!")
			*w = "Warning message here!"
		})
	}()
}

Demo

https://formdemo.cj-jackson.com/

Buy me a beer!

Bitcoin - 1MieXR5ANYY6VstNanhuLRtGQGn6zpjxK3

Documentation

Overview

Form Rendering and Validation System.

Usage

package main

import (
	"fmt"
	"io"
	"mime/multipart"
	"net/http"

	"github.com/cjtoolkit/form"
	_ "github.com/cjtoolkit/form/lang/enGB"
)

type TestForm struct {
	Text string
	File *multipart.FileHeader
}

func (t *TestForm) CJForm(f *form.Fields) {
	// Text
	func() {
		f := f.Init(&t.Text, "Text", form.InputText)
		html := f.HTML()
		html.Before = "<h1>File Test</h1>"
	}()

	// File
	func() {
		f := f.Init(&t.File, "File", form.InputFile)
		file := f.File()
		file.Size = 10 * 1024 * 1024
		file.Accept = []string{"image/jpeg", "image/png"}
	}()
}

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		f := &TestForm{}
		v := form.New(req, nil, "en-GB")
		get := func() {
			res.Header().Set("Content-Type", "text/html")

			fmt.Fprint(res, `<form action="/" method="post" enctype="multipart/form-data">
`)
			v.Render(res, f)

			fmt.Fprint(res, `<input type="submit" name="submit" value="Submit">
</form>`)
		}

		switch req.Method {
		case "GET":
			get()
		case "POST":
			req.ParseMultipartForm(10 * 1024 * 1024)
			if !v.MustValidate(f) && f.File == nil {
				get()
				return
			}

			file, _ := f.File.Open()
			io.Copy(res, file)
		}
	})

	http.ListenAndServe(":8080", mux)
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func RenderAttr

func RenderAttr(attr map[string]string) (str string)

Render Attribute into strings.

func StartingDayOfWeek

func StartingDayOfWeek(year, week int, loc *time.Location) time.Time

Get time with the starting day of that week in that year!

func WeekInAYear

func WeekInAYear(year int, loc *time.Location) int

Get number of weeks in a year, can be either 52 or 53!

Types

type Field

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

type FieldFuncs

type FieldFuncs map[string]func(m map[string]interface{})

For keeping a list of enclosed functions for struct pointer fields.

func (FieldFuncs) Attr

func (fns FieldFuncs) Attr(attr map[string]string)

Attribute

func (FieldFuncs) Call

func (fns FieldFuncs) Call(name string, m map[string]interface{})

Attemp to call a function in FieldFuncs. Does not call if function does not exist.

func (FieldFuncs) Custom

func (fns FieldFuncs) Custom(fn func(*error, *string))

Custom Rules

func (FieldFuncs) EmailError

func (fns FieldFuncs) EmailError(err string)

Custom Email Error

func (FieldFuncs) File

func (fns FieldFuncs) File() *File

File

func (FieldFuncs) HTML

func (fns FieldFuncs) HTML() *HTML

HTML

func (FieldFuncs) Label

func (fns FieldFuncs) Label() *Label

Label

func (FieldFuncs) Mandatory

func (fns FieldFuncs) Mandatory() *string

Make Field Mandatory

func (FieldFuncs) MustMatch

func (fns FieldFuncs) MustMatch() *MustMatch

Must Match Field

func (FieldFuncs) Options

func (fns FieldFuncs) Options(v interface{})

Append Options, accept []Option, []OptionInt, []OptionFloat

func (FieldFuncs) Pattern

func (fns FieldFuncs) Pattern(re *regexp.Regexp) *string

Regular Expression

func (FieldFuncs) Radios

func (fns FieldFuncs) Radios(v interface{})

Append Radios, accept []Radio, []RadioInt, []RadioFloat

func (FieldFuncs) RangeFloat

func (fns FieldFuncs) RangeFloat() *RangeFloat

Range of Float Field

func (FieldFuncs) RangeInt

func (fns FieldFuncs) RangeInt() *RangeInt

Range of Integer Field

func (FieldFuncs) RangeTime

func (fns FieldFuncs) RangeTime() *RangeTime

Range of Time Field

func (FieldFuncs) Size

func (fns FieldFuncs) Size() *Size

Size of Field

func (FieldFuncs) StepFloat

func (fns FieldFuncs) StepFloat(f float64) *string

Number of Step Float64

func (FieldFuncs) StepInt

func (fns FieldFuncs) StepInt(i int64) *string

Number of Step (int64)

func (FieldFuncs) Textarea

func (fns FieldFuncs) Textarea(rows, cols int)

Rows and Columns

type Fields

type Fields struct {
	R *http.Request
	// contains filtered or unexported fields
}

Fields

func (*Fields) Init

func (f *Fields) Init(ptr interface{}, inputName string, typeCode TypeCode) FieldFuncs

Init Field

func (*Fields) Validating

func (f *Fields) Validating() bool

Is it in progress of validation?

type File

type File struct {
	Size      int64
	SizeErr   string
	Accept    []string
	AcceptErr string
}

File

type FirstLayer

type FirstLayer interface {
	Render(w io.Writer)
}

FirstLayer Interface

type FirstLayerInput

type FirstLayerInput struct {
	Attr  map[string]string
	Label string
}

First Layer Input

func (*FirstLayerInput) Render

func (f *FirstLayerInput) Render(w io.Writer)

Render

type FirstLayerSelect

type FirstLayerSelect struct {
	Attr    map[string]string
	Options []Option
}

First Layer Select

func (*FirstLayerSelect) Render

func (f *FirstLayerSelect) Render(w io.Writer)

Render

type FirstLayerStack

type FirstLayerStack []FirstLayer

First Layer Stack

func (FirstLayerStack) Render

func (f FirstLayerStack) Render(w io.Writer)

Render

type FirstLayerTextarea

type FirstLayerTextarea struct {
	Attr    map[string]string
	Content string
}

First Layer Textarea

func (*FirstLayerTextarea) Render

func (f *FirstLayerTextarea) Render(w io.Writer)

Render

type Form

type Form interface {
	// Renders 'formPtr' to 'w', panic if formPtr is not a struct with pointer.
	// Also renders validation errors if 'Validate' or 'MustValidate' was call before hand.
	Render(w io.Writer, formPtr FormPtr)
	// As Render but Return string
	RenderStr(formPtr FormPtr) string

	// Validate User Input and Populate Field in struct with pointers.
	// Must use struct with pointers otherwise it will return an error.
	// r cannot be 'nil'
	Validate(formPtrs ...FormPtr) (bool, error)
	// Same as validate but panic on error.
	MustValidate(formPtrs ...FormPtr) bool

	// Validate Single Field, won't work with must match.
	ValidateSingle(formPtr FormPtr, name string, value []string) (err error)

	// Encode JSON into 'w'
	// {"valid": bool, "data":[{"valid":bool, "error":"", "warning":"", "name":"", "count":int}...]}
	// Must call Validate or MustValidate first, otnilherwise it's print invalid data.
	Json(w io.Writer)

	// Set Location
	Location(loc *time.Location)
}

Form Renderer and Validator interface!

func New

func New(r *http.Request, rsl RenderSecondLayer, languageSources ...string) Form

Create new form validator and renderer. Panic if unable to verify languageSources or r is nil To use Default Second Layer specify rsl as 'nil'.

Note: Stick to one instant per user request, do not use it as a global variable, as it's not thread safe.

type FormPtr

type FormPtr interface {
	CJForm(*Fields)
}

Interface

type HTML

type HTML struct {
	Before string
	After  string
}

HTML

type Label

type Label struct {
	Content, For string
	Attr         map[string]string
}

Label

type MustMatch

type MustMatch struct {
	Name  string
	Value *string
	Err   string
}

Must Match Field

type Option

type Option struct {
	Content  string
	Value    string
	Label    string
	Selected bool
	Attr     map[string]string
}

For use with Select (string, []string)

Example
return FieldFuncs{
	"form": func(m map[string]interface{}) {
		*(m["type"].(*TypeCode)) = Select
	},
	"radio": func(m map[string]interface{}) {
		*(m["radio"].(*[]Option)) = []Option{
			{Content: "Car", Value: "car", Label: "Car"},
			{Content: "Motorbike", Value: "motorbike", Label: "Motorbike"},
		}
	},
}
Output:

type OptionFloat

type OptionFloat struct {
	Content  string
	Value    float64
	Label    string
	Selected bool
	Attr     map[string]string
}

For use with Select (float64, []float64)

Example
return FieldFuncs{
	"form": func(m map[string]interface{}) {
		*(m["type"].(*TypeCode)) = Select
	},
	"radio": func(m map[string]interface{}) {
		*(m["radio"].(*[]OptionFloat)) = []OptionFloat{
			{Content: "Car", Value: 1.5, Label: "Car"},
			{Content: "Motorbike", Value: 2.5, Label: "Motorbike"},
		}
	},
}
Output:

type OptionInt

type OptionInt struct {
	Content  string
	Value    int64
	Label    string
	Selected bool
	Attr     map[string]string
}

For use with Select (int64, []int64)

Example
return FieldFuncs{
	"form": func(m map[string]interface{}) {
		*(m["type"].(*TypeCode)) = Select
	},
	"radio": func(m map[string]interface{}) {
		*(m["radio"].(*[]OptionInt)) = []OptionInt{
			{Content: "Car", Value: 1, Label: "Car"},
			{Content: "Motorbike", Value: 2, Label: "Motorbike"},
		}
	},
}
Output:

type Radio

type Radio struct {
	Value    string
	Label    string
	Selected bool
	Attr     map[string]string
}

For use with InputRadio (string)

Example
return FieldFuncs{
	"form": func(m map[string]interface{}) {
		*(m["type"].(*TypeCode)) = InputRadio
	},
	"radio": func(m map[string]interface{}) {
		*(m["radio"].(*[]Radio)) = []Radio{
			{Value: "car", Label: "Car"},
			{Value: "motorbike", Label: "Motorbike"},
		}
	},
}
Output:

type RadioFloat

type RadioFloat struct {
	Value    float64
	Label    string
	Selected bool
	Attr     map[string]string
}

For use with InputRadio (float64)

Example
return FieldFuncs{
	"form": func(m map[string]interface{}) {
		*(m["type"].(*TypeCode)) = InputRadio
	},
	"radio": func(m map[string]interface{}) {
		*(m["radio"].(*[]RadioFloat)) = []RadioFloat{
			{Value: 1.5, Label: "Car"},
			{Value: 2.5, Label: "Motorbike"},
		}
	},
}
Output:

type RadioInt

type RadioInt struct {
	Value    int64
	Label    string
	Selected bool
	Attr     map[string]string
}

For use with InputRadio (int64)

Example
return FieldFuncs{
	"form": func(m map[string]interface{}) {
		*(m["type"].(*TypeCode)) = InputRadio
	},
	"radio": func(m map[string]interface{}) {
		*(m["radio"].(*[]RadioInt)) = []RadioInt{
			{Value: 1, Label: "Car"},
			{Value: 2, Label: "Motorbike"},
		}
	},
}
Output:

type RangeFloat

type RangeFloat struct {
	Min, Max       float64
	MinErr, MaxErr string
}

Range of Float Field

type RangeInt

type RangeInt struct {
	Min, Max       int64
	MinErr, MaxErr string
}

Range of Integer Field

type RangeTime

type RangeTime struct {
	Min, Max       time.Time
	MinErr, MaxErr string
}

Range of Time Field

type RenderData

type RenderData struct {
	Name             string
	Count            int
	Type             TypeCode
	Error            error
	Warning          string
	Fns              FieldFuncs
	Check            bool
	FirstLayerStacks FirstLayerStack
}

For use with RenderSecondLayer

type RenderSecondLayer

type RenderSecondLayer interface {
	Render(w io.Writer, r RenderData)
}

Second Layer interface

var DefaultRenderSecondLayer RenderSecondLayer = RenderSecondLayerFunc(defaultRenderSecondLayer)

Default Second Layer

type RenderSecondLayerFunc

type RenderSecondLayerFunc func(w io.Writer, r RenderData)

An function adapter for 'RenderSecondLayer'

func (RenderSecondLayerFunc) Render

func (render RenderSecondLayerFunc) Render(w io.Writer, r RenderData)

A method that just calls the function.

type Size

type Size struct {
	Min, Max       int
	MinErr, MaxErr string
}

Size of Field

type TypeCode

type TypeCode uint8

For expressing form input type, eg. <input type="text"... , <textarea....

const (
	Invalid TypeCode = iota
	InputCheckbox
	InputColor
	InputDate
	InputDatetime
	InputDatetimeLocal
	InputEmail
	InputFile
	InputHidden
	InputMonth
	InputNumber
	InputPassword
	InputRadio
	InputRange
	InputSearch
	InputTel
	InputText
	InputTime
	InputUrl
	InputWeek
	Select
	Textarea
)

List of avaliable form input type, 'Invalid' does not count!

Directories

Path Synopsis
Form Util: similar to ParseForm, ParseMultipartForm from http.Request, except it's cohesive rather than coupled, Request Body and Url Query string are kept separate.
Form Util: similar to ParseForm, ParseMultipartForm from http.Request, except it's cohesive rather than coupled, Request Body and Url Query string are kept separate.
lang
enGB
English (British)
English (British)
enUS
English (American)
English (American)
secondlayer
bootstrap
Bootstrap Second Layer (http://getbootstrap.com/)
Bootstrap Second Layer (http://getbootstrap.com/)
data
Data Harvest.
Data Harvest.
foundation
Foundation Second Layer (http://foundation.zurb.com/)
Foundation Second Layer (http://foundation.zurb.com/)

Jump to

Keyboard shortcuts

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