1
1
import * as React from 'react' ;
2
2
import { connect } from 'react-redux' ;
3
3
import MetaAction from '../store/meta/MetaAction' ;
4
-
4
+ import { Field , FormProps , reduxForm } from 'redux-form' ;
5
5
6
6
const mapStateToProps = ( state ) => ( { } ) ;
7
7
@@ -11,70 +11,216 @@ const mapDispatchToProps = (dispatch) => ({
11
11
12
12
class Contact extends React . Component {
13
13
14
+ _handleSubmitHandler = ( formData ) => this . _onFormSubmit ( formData ) ;
15
+
14
16
componentWillMount ( ) {
15
17
this . props . setMeta ( { title : 'Contact Page' } ) ;
16
18
}
17
19
18
20
render ( ) {
21
+ const { handleSubmit, reset} = this . props ;
22
+
19
23
return (
20
24
< div >
21
25
< div className = "jumbotron" >
22
26
< h1 className = "display-3" > { 'Contact' } </ h1 >
23
27
< p className = "lead" > { 'This contact form uses redux-form to do client-side validation.' } </ p >
24
28
</ div >
25
- < form >
29
+ < form onSubmit = { handleSubmit ( this . _handleSubmitHandler ) } >
30
+ < div className = "form-group" >
31
+ < Field
32
+ component = { this . _renderInputField }
33
+ label = "Name"
34
+ name = "name"
35
+ placeholder = ""
36
+ type = "text"
37
+ />
38
+ </ div >
26
39
< div className = "form-group" >
27
- < label htmlFor = "emailInput" > { 'Email' } </ label >
28
- < input type = "email" className = "form-control" id = "emailInput" placeholder = "Enter email" />
40
+ < Field
41
+ component = { this . _renderInputField }
42
+ label = "Email"
43
+ name = "email"
44
+ placeholder = "example@example.com"
45
+ type = "email"
46
+ />
29
47
< small id = "emailHelp" className = "form-text text-muted" > { 'We\'ll never share your email with anyone else.' } </ small >
30
48
</ div >
31
49
< div className = "form-group" >
32
50
< label htmlFor = "exampleSelect1" > { 'Example select' } </ label >
33
- < select className = "form-control" id = "exampleSelect1" >
51
+ < Field
52
+ name = "exampleSelect1"
53
+ className = "form-control"
54
+ component = "select"
55
+ >
34
56
< option > 1</ option >
35
57
< option > 2</ option >
36
58
< option > 3</ option >
37
59
< option > 4</ option >
38
60
< option > 5</ option >
39
- </ select >
61
+ </ Field >
40
62
</ div >
41
63
< div className = "form-group" >
42
- < label htmlFor = "messageTextArea" > { 'Message' } </ label >
43
- < textarea className = "form-control" id = "messageTextArea" rows = "3" > </ textarea >
64
+ < Field
65
+ component = { this . _renderTextArea }
66
+ label = "Message"
67
+ name = "message"
68
+ placeholder = ""
69
+ />
44
70
</ div >
45
71
< fieldset className = "form-group" >
46
- < legend > { 'Radio buttons' } </ legend >
47
- < div className = "form-check" >
48
- < label className = "form-check-label" >
49
- < input type = "radio" className = "form-check-input" name = "codeQualityRadio" id = "codeQualityRadio1" value = "option1" defaultChecked />
50
- { 'This code is awesome!' }
51
- </ label >
52
- </ div >
53
- < div className = "form-check" >
54
- < label className = "form-check-label" >
55
- < input type = "radio" className = "form-check-input" name = "codeQualityRadio" id = "codeQualityRadio2" value = "option2" />
56
- { 'This code is ok.' }
57
- </ label >
58
- </ div >
59
- < div className = "form-check disabled" >
60
- < label className = "form-check-label" >
61
- < input type = "radio" className = "form-check-input" name = "codeQualityRadio" id = "codeQualityRadio3" value = "option3" disabled />
62
- { 'This code is bad' }
63
- </ label >
64
- </ div >
72
+ < legend > { 'Code Quality' } </ legend >
73
+
74
+ < Field
75
+ component = { this . _renderRadio }
76
+ label = "This code is awesome!"
77
+ name = "codeQualityRadio"
78
+ option = "1"
79
+ checked = { true }
80
+ />
81
+ < Field
82
+ component = { this . _renderRadio }
83
+ label = "This code is ok."
84
+ name = "codeQualityRadio"
85
+ option = "2"
86
+ />
87
+ < Field
88
+ component = { this . _renderRadio }
89
+ label = "This code is bad."
90
+ name = "codeQualityRadio"
91
+ option = "3"
92
+ disabled = { true }
93
+ />
65
94
</ fieldset >
66
95
< div className = "form-check" >
67
- < label className = "form-check-label" >
68
- < input type = "checkbox" className = "form-check-input" />
69
- { 'Did you star my repo?' }
70
- </ label >
96
+ < Field
97
+ component = { this . _renderCheckbox }
98
+ label = "Did you star my repo?"
99
+ name = "starred"
100
+ type = "checkbox"
101
+ />
71
102
</ div >
72
- < button type = "submit" className = "btn btn-primary" > { 'Submit' } </ button >
103
+ < button
104
+ type = "submit"
105
+ className = "btn btn-primary"
106
+ >
107
+ { 'Submit' }
108
+ </ button >
109
+ < button
110
+ type = "submit"
111
+ className = "btn btn-primary"
112
+ onClick = { reset }
113
+ >
114
+ { 'Reset' }
115
+ </ button >
73
116
</ form >
74
117
</ div >
75
118
) ;
76
119
}
77
120
121
+ _onFormSubmit ( formData ) {
122
+ console . log ( formData ) ;
123
+
124
+ window . alert ( JSON . stringify ( formData , null , 2 ) ) ;
125
+ }
126
+
127
+ _renderInputField ( field ) {
128
+ const { meta : { touched, error} } = field ;
129
+ const className = `small text-danger ${ touched && error ? '' : 'd-none' } ` ;
130
+
131
+ return (
132
+ < span >
133
+ < label htmlFor = { field . input . name } >
134
+ { field . label } < span className = { className } > { error } </ span >
135
+ </ label >
136
+ < input
137
+ { ...field . input }
138
+ className = "form-control"
139
+ id = { field . input . name }
140
+ placeholder = { field . placeholder }
141
+ type = { field . type }
142
+ />
143
+ </ span >
144
+ ) ;
145
+ }
146
+
147
+ _renderCheckbox ( field ) {
148
+ return (
149
+ < label
150
+ className = "form-check-label"
151
+ htmlFor = { field . input . name }
152
+ >
153
+ < input
154
+ { ...field . input }
155
+ className = "form-check-input"
156
+ type = "checkbox"
157
+ />
158
+ { field . label }
159
+ </ label >
160
+ ) ;
161
+ }
162
+
163
+ _renderRadio ( field ) {
164
+ return (
165
+ < div className = "form-check" >
166
+ < label className = "form-check-label" >
167
+ < input
168
+ { ...field . input }
169
+ type = "radio"
170
+ className = "form-check-input"
171
+ name = { field . input . name }
172
+ value = { field . option }
173
+ disabled = { field . disabled }
174
+ checked = { field . checked }
175
+ />
176
+ { field . label }
177
+ </ label >
178
+ </ div >
179
+ ) ;
180
+ }
181
+
182
+ _renderTextArea ( field ) {
183
+ const { meta : { touched, error } } = field ;
184
+ const className = `small text-danger ${ touched && error ? '' : 'd-none' } ` ;
185
+
186
+ return (
187
+ < span >
188
+ < label htmlFor = { field . input . name } >
189
+ { field . label } < span className = { className } > { error } </ span >
190
+ </ label >
191
+ < textarea
192
+ { ...field . input }
193
+ className = "form-control"
194
+ placeholder = { field . placeholder }
195
+ rows = "3"
196
+ >
197
+ </ textarea >
198
+ </ span >
199
+ ) ;
200
+ }
201
+
78
202
}
79
203
80
- export default connect ( mapStateToProps , mapDispatchToProps ) ( Contact ) ;
204
+ Contact = connect ( mapStateToProps , mapDispatchToProps ) ( Contact ) ;
205
+
206
+ export default reduxForm ( {
207
+ form : 'contactForm' ,
208
+ validate : ( formData ) => {
209
+ const errors = { } ;
210
+ const validEmailRegex = / ^ [ A - Z 0 - 9 . _ % + - ] + @ [ A - Z 0 - 9 . - ] + \. [ A - Z ] { 2 , 4 } $ / i;
211
+
212
+ if ( ! validEmailRegex . test ( formData . email ) ) {
213
+ errors . email = 'Invalid email address' ;
214
+ }
215
+
216
+ if ( ! formData . name ) {
217
+ errors . name = 'Required' ;
218
+ }
219
+
220
+ if ( ! formData . message ) {
221
+ errors . message = 'Required' ;
222
+ }
223
+
224
+ return errors ;
225
+ } ,
226
+ } ) ( Contact ) ;
0 commit comments