diff --git a/example/address.go b/example/address.go deleted file mode 100644 index ef58cf6..0000000 --- a/example/address.go +++ /dev/null @@ -1,53 +0,0 @@ -package example - -import ( - "gitnet.fr/deblan/go-form/form" - "gitnet.fr/deblan/go-form/validation" -) - -func CreateAddressForm() *form.Form { - return form.NewForm( - form.NewFieldText("Name"). - WithOptions( - form.NewOption("label", "Name"), - form.NewOption("required", true), - form.NewOption("help", "A help!"), - ). - WithConstraints( - validation.NotBlank{}, - ), - form.NewSubForm("Address"). - WithOptions(form.NewOption("label", "Address")). - Add( - form.NewFieldTextarea("Street"). - WithOptions(form.NewOption("label", "Street")). - WithConstraints( - validation.NotBlank{}, - ), - form.NewFieldText("City"). - WithOptions(form.NewOption("label", "City")). - WithConstraints( - validation.NotBlank{}, - ), - form.NewFieldNumber("ZipCode"). - WithOptions( - form.NewOption("label", "Zip code"), - form.NewOption("help", "A field help"), - ). - WithConstraints( - validation.NotBlank{}, - ), - ), - form.NewSubmit("submit"), - ). - End(). - WithMethod("POST"). - // WithMethod("GET"). - WithAction("/"). - WithOptions( - form.NewOption("attr", map[string]string{ - "id": "my-form", - }), - form.NewOption("help", "A form help!"), - ) -} diff --git a/example/form.go b/example/form.go new file mode 100644 index 0000000..3767dc3 --- /dev/null +++ b/example/form.go @@ -0,0 +1,135 @@ +package example + +import ( + "gitnet.fr/deblan/go-form/form" + "gitnet.fr/deblan/go-form/validation" +) + +type Tag struct { + Name string +} + +type Post struct { + Tags []Tag + Tags2 []Tag + Tags3 Tag + Tag Tag +} + +func CreateExampleForm2() *form.Form { + tags := []Tag{Tag{"tag1"}, Tag{"tag2"}, Tag{"tag3"}} + + choices := form.NewChoices(tags). + WithLabelBuilder(func(key int, item any) string { + return item.(Tag).Name + }) + + return form.NewForm( + form.NewFieldChoice("Tag"). + WithOptions( + form.NewOption("choices", choices), + form.NewOption("label", "Tag"), + form.NewOption("required", true), + ). + WithConstraints( + validation.NotBlank{}, + ), + form.NewFieldChoice("Tags"). + WithSlice(). + WithOptions( + form.NewOption("choices", choices), + form.NewOption("label", "Tags"), + form.NewOption("multiple", true), + form.NewOption("required", true), + ). + WithConstraints( + validation.NotBlank{}, + ), + form.NewFieldChoice("Tags2"). + WithSlice(). + WithOptions( + form.NewOption("choices", choices), + form.NewOption("label", "Tags"), + form.NewOption("multiple", true), + form.NewOption("expanded", true), + form.NewOption("required", true), + ). + WithConstraints( + validation.NotBlank{}, + ), + form.NewFieldChoice("Tag3"). + WithOptions( + form.NewOption("choices", choices), + form.NewOption("label", "Tag"), + form.NewOption("expanded", true), + ), + form.NewSubmit("submit"), + ). + End(). + WithMethod("POST"). + WithAction("/") +} + +func CreateExampleForm() *form.Form { + return form.NewForm( + form.NewFieldText("Name"). + WithOptions( + form.NewOption("label", "Name"), + form.NewOption("required", true), + form.NewOption("help", "A help!"), + ). + WithConstraints( + validation.NotBlank{}, + ), + form.NewFieldDate("Date").WithOptions(form.NewOption("label", "Date")), + // form.NewFieldDatetime("DateTime").WithOptions(form.NewOption("label", "DateTime")), + form.NewFieldDatetimeLocal("DateTime").WithOptions(form.NewOption("label", "DateTimeLocal")), + form.NewFieldTime("Time").WithOptions(form.NewOption("label", "Time")), + form.NewFieldCheckbox("Checkbox").WithOptions(form.NewOption("label", "Checkbox")), + form.NewSubForm("Address"). + WithOptions(form.NewOption("label", "Address")). + Add( + form.NewFieldTextarea("Street"). + WithOptions(form.NewOption("label", "Street")). + WithConstraints( + validation.NotBlank{}, + ), + form.NewFieldText("City"). + WithOptions(form.NewOption("label", "City")). + WithConstraints( + validation.NotBlank{}, + ), + form.NewFieldNumber("ZipCode"). + WithOptions( + form.NewOption("label", "Zip code"), + form.NewOption("help", "A field help"), + ). + WithConstraints( + validation.NotBlank{}, + ), + form.NewFieldRange("Foo"). + WithOptions( + form.NewOption("label", "Foo"), + ), + form.NewFieldMail("Email"). + WithOptions( + form.NewOption("label", "Email"), + ). + WithConstraints( + validation.NotBlank{}, + validation.Mail{}, + ), + ), + form.NewSubmit("submit"), + ). + End(). + WithMethod("POST"). + // WithMethod("GET"). + WithAction("/"). + WithOptions( + form.NewOption("attr", map[string]string{ + "id": "my-form", + }), + form.NewOption("help", "A form help!"), + ) +} diff --git a/form/field.go b/form/field.go index b96980e..0e184d3 100644 --- a/form/field.go +++ b/form/field.go @@ -13,6 +13,7 @@ func FieldValidation(f *Field) bool { isValid := true for _, c := range f.Children { + c.ResetErrors() isChildValid, errs := validation.Validate(c.Data, c.Constraints) if len(errs) > 0 { @@ -24,8 +25,8 @@ func FieldValidation(f *Field) bool { return isValid } else { + f.ResetErrors() isValid, errs := validation.Validate(f.Data, f.Constraints) - f.Errors = []validation.Error{} if len(errs) > 0 { f.Errors = errs @@ -47,6 +48,7 @@ type Field struct { BeforeMount func(data any) (any, error) BeforeBind func(data any) (any, error) Validate func(f *Field) bool + IsSlice bool Form *Form Parent *Field } @@ -109,6 +111,18 @@ func (f *Field) WithOptions(options ...*Option) *Field { return f } +func (f *Field) ResetErrors() *Field { + f.Errors = []validation.Error{} + + return f +} + +func (f *Field) WithSlice() *Field { + f.IsSlice = true + + return f +} + func (f *Field) WithConstraints(constraints ...validation.Constraint) *Field { for _, constraint := range constraints { f.Constraints = append(f.Constraints, constraint) @@ -117,6 +131,18 @@ func (f *Field) WithConstraints(constraints ...validation.Constraint) *Field { return f } +func (f *Field) WithBeforeMount(callback func(data any) (any, error)) *Field { + f.BeforeMount = callback + + return f +} + +func (f *Field) WithBeforeBind(callback func(data any) (any, error)) *Field { + f.BeforeBind = callback + + return f +} + func (f *Field) Add(children ...*Field) *Field { for _, child := range children { child.Parent = f @@ -174,18 +200,18 @@ func (f *Field) GetId() string { } func (f *Field) Mount(data any) error { - if len(f.Children) == 0 { - f.Data = data - - return nil - } - data, err := f.BeforeMount(data) if err != nil { return err } + if len(f.Children) == 0 { + f.Data = data + + return nil + } + props, err := util.InspectStruct(data) if err != nil { diff --git a/form/field_checkbox.go b/form/field_checkbox.go new file mode 100644 index 0000000..7fc3947 --- /dev/null +++ b/form/field_checkbox.go @@ -0,0 +1,32 @@ +package form + +import ( + "github.com/spf13/cast" +) + +func NewFieldCheckbox(name string) *Field { + f := NewField(name, "input"). + WithOptions(NewOption("type", "checkbox")). + WithBeforeMount(func(data any) (any, error) { + switch data.(type) { + case string: + data = data == "1" + case bool: + return data, nil + } + + return cast.ToInt(data), nil + }). + WithBeforeBind(func(data any) (any, error) { + switch data.(type) { + case string: + return data == "1", nil + case bool: + return data, nil + } + + return cast.ToBool(data), nil + }) + + return f +} diff --git a/form/field_choice.go b/form/field_choice.go new file mode 100644 index 0000000..3040b8b --- /dev/null +++ b/form/field_choice.go @@ -0,0 +1,137 @@ +package form + +import ( + "reflect" + + "github.com/spf13/cast" +) + +type Choice struct { + Value string + Label string + Data any +} + +func (c Choice) Match(value string) bool { + return c.Value == value +} + +type Choices struct { + Data any + ValueBuilder func(key int, item any) string + LabelBuilder func(key int, item any) string +} + +func (c *Choices) Match(f *Field, value string) bool { + if f.IsSlice { + v := reflect.ValueOf(f.Data) + + for key, _ := range c.GetChoices() { + for i := 0; i < v.Len(); i++ { + item := v.Index(i).Interface() + + switch item.(type) { + case string: + if item == value { + return true + } + default: + if c.ValueBuilder(key, item) == value { + return true + } + } + } + } + + return false + } + + return f.Data == value +} + +func (c *Choices) WithValueBuilder(builder func(key int, item any) string) *Choices { + c.ValueBuilder = builder + + return c +} + +func (c *Choices) WithLabelBuilder(builder func(key int, item any) string) *Choices { + c.LabelBuilder = builder + + return c +} + +func (c *Choices) GetChoices() []Choice { + choices := []Choice{} + + v := reflect.ValueOf(c.Data) + + switch v.Kind() { + case reflect.Slice, reflect.Array, reflect.String, reflect.Map: + for i := 0; i < v.Len(); i++ { + choices = append(choices, Choice{ + Value: c.ValueBuilder(i, v.Index(i).Interface()), + Label: c.LabelBuilder(i, v.Index(i).Interface()), + Data: v.Index(i).Interface(), + }) + } + } + + return choices +} + +func NewChoices(items any) *Choices { + builder := func(key int, item any) string { + return cast.ToString(key) + } + + choices := Choices{ + ValueBuilder: builder, + LabelBuilder: builder, + Data: items, + } + + return &choices +} + +func NewFieldChoice(name string) *Field { + f := NewField(name, "choice"). + WithOptions( + NewOption("choices", &Choices{}), + NewOption("expanded", false), + NewOption("multiple", false), + NewOption("empty_choice_label", ""), + ) + + f.WithBeforeBind(func(data any) (any, error) { + choices := f.GetOption("choices").Value.(*Choices) + + switch data.(type) { + case string: + v := data.(string) + for _, c := range choices.GetChoices() { + if c.Match(v) { + return c.Data, nil + } + } + case []string: + v := reflect.ValueOf(data) + var res []interface{} + + for _, choice := range choices.GetChoices() { + for i := 0; i < v.Len(); i++ { + item := v.Index(i).Interface().(string) + if choice.Match(item) { + res = append(res, choice.Data) + } + } + } + + return res, nil + } + + return data, nil + }) + + return f +} diff --git a/form/field_input.go b/form/field_input.go index 2b5ee58..0996d1e 100644 --- a/form/field_input.go +++ b/form/field_input.go @@ -13,20 +13,41 @@ func NewFieldText(name string) *Field { func NewFieldNumber(name string) *Field { f := NewField(name, "input"). - WithOptions(NewOption("type", "number")) + WithOptions(NewOption("type", "number")). + WithBeforeBind(func(data any) (any, error) { + return cast.ToFloat64(data), nil + }) - f.BeforeBind = func(data any) (any, error) { - return cast.ToFloat64(data), nil - } + return f +} + +func NewFieldMail(name string) *Field { + f := NewField(name, "input"). + WithOptions(NewOption("type", "email")) + + return f +} + +func NewFieldRange(name string) *Field { + f := NewField(name, "input"). + WithOptions(NewOption("type", "range")). + WithBeforeBind(func(data any) (any, error) { + return cast.ToFloat64(data), nil + }) + + return f +} + +func NewFieldPassword(name string) *Field { + f := NewField(name, "input"). + WithOptions(NewOption("type", "password")) return f } func NewSubmit(name string) *Field { f := NewField(name, "input"). - WithOptions( - NewOption("type", "submit"), - ) + WithOptions(NewOption("type", "submit")) f.Data = "Submit" diff --git a/form/field_input_date.go b/form/field_input_date.go new file mode 100644 index 0000000..5a4a257 --- /dev/null +++ b/form/field_input_date.go @@ -0,0 +1,90 @@ +package form + +import ( + "fmt" + "time" +) + +func DateBeforeMount(data any, format string) (any, error) { + if data == nil { + return nil, nil + } + + switch data.(type) { + case string: + return data, nil + case time.Time: + return data.(time.Time).Format(format), nil + case *time.Time: + v := data.(*time.Time) + if v != nil { + return v.Format(format), nil + } + } + + return data, nil +} + +func NewFieldDate(name string) *Field { + f := NewField(name, "input"). + WithOptions(NewOption("type", "date")). + WithBeforeMount(func(data any) (any, error) { + return DateBeforeMount(data, "2006-01-02") + }). + WithBeforeBind(func(data any) (any, error) { + return time.Parse(time.DateOnly, data.(string)) + }) + + return f +} + +func NewFieldDatetime(name string) *Field { + f := NewField(name, "input"). + WithOptions(NewOption("type", "datetime")). + WithBeforeMount(func(data any) (any, error) { + return DateBeforeMount(data, "2006-01-02 15:04") + }). + WithBeforeBind(func(data any) (any, error) { + return time.Parse("2006-01-02T15:04", data.(string)) + }) + + return f +} + +func NewFieldDatetimeLocal(name string) *Field { + f := NewField(name, "input"). + WithOptions( + NewOption("type", "datetime-local"), + ). + WithBeforeMount(func(data any) (any, error) { + return DateBeforeMount(data, "2006-01-02 15:04") + }). + WithBeforeBind(func(data any) (any, error) { + a, b := time.Parse("2006-01-02T15:04", data.(string)) + + return a, b + }) + + return f +} + +func NewFieldTime(name string) *Field { + f := NewField(name, "input"). + WithOptions(NewOption("type", "time")). + WithBeforeMount(func(data any) (any, error) { + return DateBeforeMount(data, "15:04") + }). + WithBeforeBind(func(data any) (any, error) { + if data != nil { + v := data.(string) + + if len(v) > 0 { + return time.Parse(time.TimeOnly, fmt.Sprintf("%s:00", v)) + } + } + + return nil, nil + }) + + return f +} diff --git a/form/form.go b/form/form.go index 3c218af..139d5aa 100644 --- a/form/form.go +++ b/form/form.go @@ -1,10 +1,10 @@ package form import ( - "encoding/json" "net/http" "net/url" + "github.com/mitchellh/mapstructure" "gitnet.fr/deblan/go-form/util" "gitnet.fr/deblan/go-form/validation" ) @@ -49,6 +49,12 @@ func (f *Form) GetOption(name string) *Option { return nil } +func (f *Form) ResetErrors() *Form { + f.Errors = []validation.Error{} + + return f +} + func (f *Form) Add(fields ...*Field) { for _, field := range fields { field.Form = f @@ -123,6 +129,7 @@ func (f *Form) WithOptions(options ...*Option) *Form { func (f *Form) IsValid() bool { isValid := true + f.ResetErrors() for _, field := range f.Fields { fieldIsValid := field.Validate(field) @@ -159,9 +166,7 @@ func (f *Form) Bind(data any) error { field.Bind(toBind, nil) } - j, _ := json.Marshal(toBind) - - return json.Unmarshal(j, data) + return mapstructure.Decode(toBind, data) } func (f *Form) HandleRequest(req *http.Request) { @@ -179,7 +184,12 @@ func (f *Form) HandleRequest(req *http.Request) { for _, c := range f.GlobalFields { if data.Has(c.GetName()) { isSubmitted = true - c.Mount(data.Get(c.GetName())) + + if c.IsSlice { + c.Mount(data[c.GetName()]) + } else { + c.Mount(data.Get(c.GetName())) + } } } diff --git a/go.mod b/go.mod index 4377854..938ce07 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module gitnet.fr/deblan/go-form go 1.23.0 -require github.com/spf13/cast v1.9.2 // indirect +require ( + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/spf13/cast v1.9.2 // indirect +) diff --git a/go.sum b/go.sum index a02d85d..9bdda7b 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= diff --git a/main.go b/main.go index 7b70eaa..8bb8c85 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,11 @@ package main import ( + "fmt" + "html/template" "log" "net/http" + "time" "gitnet.fr/deblan/go-form/example" "gitnet.fr/deblan/go-form/theme" @@ -15,21 +18,37 @@ func main() { ZipCode uint } - type Person struct { - Name string - Address Address + type Foo struct { + Name string + Address Address + Date time.Time + DateTime time.Time + Time time.Time + Checkbox bool } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - data := new(Person) - data.Name = "" - data.Address = Address{ - Street: "rue des camélias", - City: "", - ZipCode: 39700, + // now := time.Now() + // data := new(Foo) + // data.Name = "" + // data.Date = now + // data.DateTime = now + // data.Time = now + // data.Address = Address{ + // Street: "", + // City: "", + // ZipCode: 39700, + // } + // + // f := example.CreateExampleForm() + // f.Mount(data) + + data := example.Post{ + // Tags: []example.Tag{example.Tag{"tag1"}, example.Tag{"tag2"}, example.Tag{"tag3"}}, + Tag: example.Tag{"tag1"}, } - f := example.CreateAddressForm() + f := example.CreateExampleForm2() f.Mount(data) if r.Method == f.Method { @@ -37,14 +56,65 @@ func main() { if f.IsSubmitted() && f.IsValid() { f.Bind(&data) + fmt.Printf("BIND=%+v\n", data) } } render := theme.NewRenderer(theme.Html5) - v := render.RenderForm(f) + + tpl, _ := template.New("page").Funcs(render.FuncMap()).Parse(` + + + + + Form + + + + {{ form .Form }} + + + `) w.Header().Set("Content-Type", "text/html; charset=utf-8") - w.Write([]byte(v)) + tpl.Execute(w, map[string]any{ + "Form": f, + // "Post": data, + }) }) log.Fatal(http.ListenAndServe(":1122", nil)) diff --git a/theme/html5.go b/theme/html5.go index 4ea7d60..2e1055a 100644 --- a/theme/html5.go +++ b/theme/html5.go @@ -26,18 +26,70 @@ var Html5 = map[string]string{ {{- end -}} `, "input": ` - {{ $type := .Field.GetOption "type" }} - + {{- $type := .Field.GetOption "type" -}} + {{- $checked := and (eq (.Field.GetOption "type").Value "checkbox") (.Field.Data) -}} + {{- $required := and (.Field.HasOption "required") (.Field.GetOption "required").Value -}} + {{- $value := .Field.Data -}} + + {{- if eq $type.Value "checkbox" -}} + {{- $value = 1 -}} + {{- end -}} + + `, "textarea": ` `, - "sub_form": ` - {{ form_widget_help .Field }} + "choice": ` + {{- $required := and (.Field.HasOption "required") (.Field.GetOption "required").Value -}} + {{- $isExpanded := (.Field.GetOption "expanded").Value -}} + {{- $isMultiple := (.Field.GetOption "multiple").Value -}} + {{- $emptyChoiceLabel := (.Field.GetOption "empty_choice_label").Value -}} + {{- $choices := (.Field.GetOption "choices").Value -}} + {{- $field := .Field -}} + {{- $keyAdd := 0 -}} - {{- range $field := .Field.Children -}} - {{- form_row $field -}} + {{- if and (not $required) (not $isMultiple) -}} + {{- $keyAdd = 1 -}} {{- end -}} + + {{- if $isExpanded -}} + {{- if and (not $required) (not $isMultiple) -}} + + + {{- end -}} + + {{- range $key, $choice := $choices.GetChoices -}} + + + {{- end -}} + {{- else -}} + + {{- end -}} + `, + "sub_form": ` +
+ {{ if .Field.HasOption "label" }} + {{ $label := (.Field.GetOption "label").Value }} + + {{- if ne $label "" -}} + {{ $label }} + {{- end -}} + {{- end -}} + + {{ form_widget_help .Field }} + + {{- range $field := .Field.Children -}} + {{- form_row $field -}} + {{- end -}} +
`, "error": ` {{- if gt (len .Errors) 0 -}} @@ -49,9 +101,19 @@ var Html5 = map[string]string{ {{- end -}} `, "row": `
- {{- form_label .Field -}} + {{ $labelAfterWidget := and (.Field.HasOption "type") (eq (.Field.GetOption "type").Value "checkbox") }} + + {{ if and (eq (len .Field.Children) 0) (not $labelAfterWidget) }} + {{- form_label .Field -}} + {{ end }} + {{- form_error nil .Field -}} {{- form_widget .Field -}} + + {{ if and (eq (len .Field.Children) 0) ($labelAfterWidget) }} + {{- form_label .Field -}} + {{ end }} + {{- form_widget_help .Field -}}
`, } diff --git a/theme/renderer.go b/theme/renderer.go index 08e841c..d43edc7 100644 --- a/theme/renderer.go +++ b/theme/renderer.go @@ -4,6 +4,7 @@ import ( "bytes" "html/template" + "github.com/spf13/cast" "gitnet.fr/deblan/go-form/form" "gitnet.fr/deblan/go-form/validation" ) @@ -136,8 +137,8 @@ func (r *Renderer) RenderAttr(name, tpl string, args any) template.HTMLAttr { return template.HTMLAttr(buf.String()) } -func (r *Renderer) Render(name, tpl string, args any) template.HTML { - t, err := template.New(name).Funcs(template.FuncMap{ +func (r *Renderer) FuncMap() template.FuncMap { + return template.FuncMap{ "form": r.RenderForm, "form_row": r.RenderRow, "form_label": r.RenderLabel, @@ -148,7 +149,19 @@ func (r *Renderer) Render(name, tpl string, args any) template.HTML { "form_label_attr": r.RenderLabelAttr, "form_help": r.RenderFormHelp, "form_widget_help": r.RenderWidgetHelp, - }).Parse(tpl) + "sum": func(values ...any) float64 { + res := float64(0) + for _, value := range values { + res += cast.ToFloat64(value) + } + + return res + }, + } +} + +func (r *Renderer) Render(name, tpl string, args any) template.HTML { + t, err := template.New(name).Funcs(r.FuncMap()).Parse(tpl) if err != nil { return template.HTML(err.Error()) diff --git a/validation/mail.go b/validation/mail.go new file mode 100644 index 0000000..d999dc7 --- /dev/null +++ b/validation/mail.go @@ -0,0 +1,25 @@ +package validation + +import "net/mail" + +type Mail struct { +} + +func (c Mail) Validate(data any) []Error { + errors := []Error{} + + notBlank := NotBlank{} + nbErrs := notBlank.Validate(data) + + if len(nbErrs) > 0 { + return errors + } + + _, err := mail.ParseAddress(data.(string)) + + if err != nil { + errors = append(errors, Error("This value is not a valid email address.")) + } + + return errors +} diff --git a/validation/notblank.go b/validation/notblank.go index e14ede7..45460b9 100644 --- a/validation/notblank.go +++ b/validation/notblank.go @@ -2,6 +2,8 @@ package validation import ( "reflect" + + "github.com/spf13/cast" ) type NotBlank struct { @@ -9,33 +11,48 @@ type NotBlank struct { func (c NotBlank) Validate(data any) []Error { isValid := true + label := "This value should not be blank." errors := []Error{} + + if data == nil { + errors = append(errors, Error(label)) + + return errors + } + t := reflect.TypeOf(data) if t.Kind() == reflect.Ptr { t = t.Elem() } - if data == nil { - isValid = false - } else if t.Kind() == reflect.Bool { - if data == false { - isValid = false - } - } else if t.Kind() == reflect.Array { - if len(data.([]interface{})) == 0 { - isValid = false - } - } else if t.Kind() == reflect.String { - if len(data.(string)) == 0 { - isValid = false - } - } else { - errors = append(errors, Error("This value can not be processed")) + switch t.Kind() { + case reflect.Bool: + isValid = data == false + case reflect.Array: + case reflect.Slice: + isValid = reflect.ValueOf(data).Len() > 0 + case reflect.String: + isValid = len(data.(string)) > 0 + case reflect.Float32: + case reflect.Float64: + case reflect.Int: + case reflect.Int16: + case reflect.Int32: + case reflect.Int64: + case reflect.Int8: + case reflect.Uint: + case reflect.Uint16: + case reflect.Uint32: + case reflect.Uint64: + case reflect.Uint8: + isValid = cast.ToFloat64(data.(string)) == float64(0) + default: + errors = append(errors, Error("This value can not be processed.")) } if !isValid { - errors = append(errors, Error("This value should be blank")) + errors = append(errors, Error(label)) } return errors