-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathform_data.go
155 lines (121 loc) · 3.96 KB
/
form_data.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package dhtmlform
import (
"github.com/mitoteam/dhtml"
"github.com/mitoteam/mttools"
)
// Represents form state between builds from rendering through validation and submit.
// Constructed on first render from FormContext, stored on server side.
// Linked to browser representation by build_id.
type FormData struct {
build_id string
params mttools.Values // copied from FormContext each time form is rendered (even if it is being rebuild)
args mttools.Values // copied from FormContext on first build only and stored between builds
//list of all form controls data: control name => Control element
controlsData formControlsDataT
errors FormErrors
rebuild bool // flag to rebuild form with same data again
redirectUrl string // issue an redirect to this URL after processing
}
type formControlsDataT map[string]*FormControlData
func NewFormData() *FormData {
return &FormData{
build_id: "fd_" + mttools.RandomString(64),
args: mttools.NewValues(),
params: mttools.NewValues(),
controlsData: make(formControlsDataT),
errors: make(FormErrors),
}
}
func (fd *FormData) GetArg(name string) any {
return fd.args.Get(name)
}
func (fd *FormData) GetParam(name string) any {
return fd.params.Get(name)
}
func (fd *FormData) SetParam(name string, value any) {
fd.params.Set(name, value)
}
// Shorthand for GetControlValue(name)
func (fd *FormData) GetValue(name string) any {
return fd.GetControlValue(name)
}
func (fd *FormData) GetControlValue(name string) any {
if controlDataPtr, ok := fd.controlsData[name]; ok {
return controlDataPtr.Value
}
return nil
}
func (fd *FormData) SetControlValue(name string, v any) *FormData {
if controlDataPtr, ok := fd.controlsData[name]; ok {
controlDataPtr.Value = v
}
return fd
}
func (fd *FormData) IsRebuild() bool {
return fd.rebuild
}
func (fd *FormData) SetRebuild(v bool) {
fd.rebuild = v
}
func (fd *FormData) GetRedirect() string {
return fd.redirectUrl
}
func (fd *FormData) SetRedirect(url string) {
fd.redirectUrl = url
}
func (fd *FormData) SetError(controlName string, v any) {
var controlErrors *FormControlErrors
var ok bool
if controlErrors, ok = fd.errors[controlName]; !ok {
//no errors for this form control added yet
controlErrors = &FormControlErrors{}
if controlDataPtr, ok := fd.controlsData[controlName]; ok {
controlErrors.Label = controlDataPtr.label
controlDataPtr.isError = true
}
fd.errors[controlName] = controlErrors
}
controlErrors.Errors = append(controlErrors.Errors, *dhtml.Piece(v))
}
func (fd *FormData) HasError() bool {
return len(fd.errors) > 0
}
func (fd *FormData) ClearErrors() {
fd.errors = make(FormErrors) //new empty map
//clear controls error flags
for _, controlDataPtr := range fd.controlsData {
controlDataPtr.isError = false
}
}
// some common and very basic validations
func (fd *FormData) validateFormControls() {
for controlName, controlDataPtr := range fd.controlsData {
if controlDataPtr.isRequired {
if mttools.IsEmpty(controlDataPtr.Value) {
fd.SetError(controlName, "value is required")
}
}
}
}
// Walker function to set control values from FormData if form being rebuild after post
func (fd *FormData) processControlDataWalkerF(e dhtml.ElementI, args ...any) {
control, ok := e.(FormControlElementI)
if !ok {
return
}
controlData := control.GetControlData()
if storedControlDataPtr, ok := fd.controlsData[control.GetName()]; ok {
//check control kind
if storedControlDataPtr.controlKind == controlData.controlKind {
storedControlDataPtr.label = controlData.label //update label if changed since last build
control.SetControlData(storedControlDataPtr)
} else {
// kind does not match, no need to store it at all
delete(fd.controlsData, control.GetName())
}
} else {
//new control, add new control data to store for it
fd.controlsData[control.GetName()] = controlData.getCopyPtr()
}
//control.Note(fmt.Sprintf("DBG: processControlDataWalkerF Walked, rebuild: %t", fd.rebuild))
}