Browse Source

Update FormField functionality

- Add new properties
- Add method to render HTML representation
- Allow validators to render multiple error messages
- Update validators error messages
Bozhin Zafirov 2 years ago
parent
commit
b546d2a266
3 changed files with 97 additions and 23 deletions
  1. 16 13
      constructors.go
  2. 75 8
      forms.go
  3. 6 2
      validate.go

+ 16 - 13
constructors.go

@@ -1,16 +1,6 @@
 package form
 
-///* Generate new CharField field with type text */
-//func NewCharField(Name string, Label *string, Value *string, Class *string, Validators *ValidatorsList) FormField {
-//	strFromPtr := func(str *string) (s string) {
-//		if str != nil {
-//			s = *str
-//		}
-//		return
-//	}
-//	return FormField{Name, strFromPtr(Label), strFromPtr(Value), strFromPtr(Class), nil, Validators}
-//}
-
+/* strFromPtr converts string pointer to a string */
 func strFromPtr(str *string) (s string) {
 	if str != nil {
 		s = *str
@@ -20,10 +10,23 @@ func strFromPtr(str *string) (s string) {
 
 /* Generate new CharField field with type text */
 func NewCharField(Name string, Value *string) *FormField {
-	return &FormField{Name, "", strFromPtr(Value), "", nil, nil}
+	return &FormField{
+		Name,
+		nil,
+		"",
+		strFromPtr(Value),
+		"form-control",
+		"text",
+		"",
+		"",
+		false,
+		false,
+		nil,
+	}
 }
 
 /* Generate new CharField field with type password */
 func NewPasswordField(Name string) *FormField {
-	return NewCharField(Name, nil)
+	field := NewCharField(Name, nil).SetType("password")
+	return &field
 }

+ 75 - 8
forms.go

@@ -1,7 +1,9 @@
 package form
 
 import (
+	"bytes"
 	"context"
+	"html/template"
 	"strconv"
 )
 
@@ -13,12 +15,17 @@ type ValidatorsList []ValidatorFunc
 
 /* A general purpose form  field struct */
 type FormField struct {
-	Name       string
-	Label      string
-	Value      string
-	Class      string
-	Error      error
-	Validators *ValidatorsList
+	Name        string
+	Error       []error
+	Value       string
+	Label       string
+	Class       string
+	Type        string
+	Placeholder string
+	Help        string
+	Required    bool
+	AutoFocus   bool
+	Validators  *ValidatorsList
 }
 
 /* SetValidators configures validators list in form field */
@@ -39,14 +46,48 @@ func (f FormField) SetClass(class string) FormField {
 	return f
 }
 
+/* SetRequired marks FormField as mandatory */
+func (f FormField) SetRequired() FormField {
+	f.Required = true
+	return f
+}
+
+/* SetAutoFocus gives focus to current FormField on page load  */
+func (f FormField) SetAutoFocus() FormField {
+	f.AutoFocus = true
+	return f
+}
+
+/* SetType specifies input field type */
+func (f FormField) SetType(t string) FormField {
+	f.Type = t
+	return f
+}
+
+/* SetPlaceholder specified a placeholder property in Formfield */
+func (f FormField) SetPlaceholder(placeholder string) FormField {
+	f.Placeholder = placeholder
+	return f
+}
+
+/* SetHelp specified a help message for current Formfield */
+func (f FormField) SetHelp(help string) FormField {
+	f.Help = help
+	return f
+}
+
 /* GetString returns FormField.Value as string */
 func (f FormField) GetString() string {
 	return f.Value
 }
 
 /* GetInt returns FormField.Value as int */
-func (f FormField) GetInt() (int, error) {
-	return strconv.Atoi(f.Value)
+func (f FormField) GetInt() (v int, err error) {
+	v, err = strconv.Atoi(f.Value)
+	if err != nil {
+		err = EInvalidIntValue
+	}
+	return
 }
 
 /* Int converts FormField.Value to integer value and ignores errors */
@@ -80,3 +121,29 @@ func (f FormField) GetBool() (bool, error) {
 func (f FormField) GetChecked() bool {
 	return f.Value == "on"
 }
+
+/* formFieldTemplate is a template to render FormField element in HTML format */
+const formFieldTemplate = `
+	{{ if .Label }}<label class="form-label" for="{{ .Name }}">{{ .Label }}</label>{{ end }}
+	<input type="{{ .Type }}" id="{{ .Name }}" name="{{ .Name }}"
+		{{- if .Class }} class="{{ .Class }}"{{ end }}
+		{{- if .Value }} value="{{ .Value }}"{{ end }}
+		{{- if .Placeholder}} placeholder="{{ .Placeholder }}"{{ end }}
+		{{- if .Help }} aria-describedby="{{ .Name }}Help"{{ end }}
+		{{- if .Required }} required{{ end }}
+		{{- if .AutoFocus }} autofocus{{ end }}>
+		{{ if .Help }}<div id="{{ .Name }}Help" class="form-text">{{ .Help }}</div>{{ end }}
+	{{ if .Error }}{{ range $e := .Error }}<div class="text-danger">{{ $e }}</div>{{ end }}{{ end }}
+`
+
+/* formTemplate is compiled template to render FormField element in HTML format */
+var formTemplate = template.Must(template.New("FormField").Parse(formFieldTemplate))
+
+/* HTML renders FormField element in html format */
+func (f FormField) HTML() template.HTML {
+	var buffer bytes.Buffer
+	if err := formTemplate.Execute(&buffer, f); err == nil {
+		return template.HTML(buffer.String())
+	}
+	return template.HTML("")
+}

+ 6 - 2
validate.go

@@ -48,13 +48,17 @@ func ValidateForm(r *http.Request, p interface{}) error {
 		if field.Validators == nil {
 			continue
 		}
+		/* prepare list of FormField errors */
+		var errors []error
 		for _, validator := range *field.Validators {
 			if err := validator(field, r.Context()); err != nil {
-				fieldn.Field(4).Set(reflect.ValueOf(err))
+				errors = append(errors, err)
 				FormError = err
-				break
 			}
 		}
+		if len(errors) != 0 {
+			fieldn.Field(1).Set(reflect.ValueOf(errors))
+		}
 	}
 
 	/* return status */