@@ -85,7 +85,7 @@ class ReactFormInputValidation extends BaseValidation {
85
85
86
86
public handleBlurEvent ( event : React . FocusEvent < HTMLInputElement > ) {
87
87
const element : HTMLInputElement = event . target ;
88
- this . validate ( element ) . then ( ( inputErrors ) => {
88
+ this . validate ( [ element ] ) . then ( ( inputErrors ) => {
89
89
if ( this . component && this . component . hasOwnProperty ( "state" ) ) {
90
90
this . errors = Object . assign ( this . errors , inputErrors ) ;
91
91
this . component . setState ( { errors : this . errors , isValidatorUpdate : true } ) ;
@@ -114,32 +114,29 @@ class ReactFormInputValidation extends BaseValidation {
114
114
} ;
115
115
}
116
116
117
- const validatePromises : Array < Promise < any > > = [ ] ;
117
+ const elements = [ ] ;
118
118
119
119
form . querySelectorAll ( "textarea,select,input:not([type='submit']):not([type='file']):not([data-ignore-validation])" )
120
120
. forEach ( ( element ) => {
121
- validatePromises . push ( this . validate ( element ) ) ;
121
+ elements . push ( element ) ;
122
122
} ) ;
123
123
124
124
return new Promise ( ( resolve ) => {
125
- Promise . all ( validatePromises )
126
- . then ( ( results ) => {
127
- results . forEach ( ( eachResult ) => {
128
- this . errors = Object . assign ( this . errors , eachResult ) ;
129
- this . component . setState ( {
130
- errors : this . errors ,
131
- isValidatorUpdate : true
132
- } ) ;
133
- } ) ;
134
-
135
- if ( Object . keys ( this . component . state . errors ) [ 0 ] &&
136
- form . querySelector ( `[name="${ Object . keys ( this . component . state . errors ) [ 0 ] } "]` ) ) {
137
- form . querySelector ( `[name="${ Object . keys ( this . component . state . errors ) [ 0 ] } "]` ) . focus ( ) ;
138
- }
139
-
140
- resolve ( Object . keys ( this . component . state . errors ) . length === 0 ) ;
141
- } )
142
- . catch ( errors => console . log ( errors ) ) ;
125
+ this . validate ( elements )
126
+ . then ( results => {
127
+ this . errors = results ;
128
+ this . component . setState ( {
129
+ errors : this . errors ,
130
+ isValidatorUpdate : true
131
+ } ) ;
132
+
133
+ if ( Object . keys ( this . component . state . errors ) [ 0 ] &&
134
+ form . querySelector ( `[name="${ Object . keys ( this . component . state . errors ) [ 0 ] } "]` ) ) {
135
+ form . querySelector ( `[name="${ Object . keys ( this . component . state . errors ) [ 0 ] } "]` ) . focus ( ) ;
136
+ }
137
+ resolve ( Object . keys ( this . component . state . errors ) . length === 0 ) ;
138
+ } )
139
+ . catch ( errors => console . log ( errors ) ) ;
143
140
} ) ;
144
141
}
145
142
@@ -166,86 +163,94 @@ class ReactFormInputValidation extends BaseValidation {
166
163
}
167
164
168
165
/**
169
- * Parse the input element base on the element type get its value and return it.
166
+ * Validate the single input element and return validation errors;
170
167
*
171
- * @param element HTMLInputElement or HTMLSelectElement
168
+ * @param element HTMLInputElement
172
169
*/
173
- private getValueFromHtmlNode ( element : HTMLInputElement | HTMLSelectElement ) : any {
174
- switch ( element . tagName ) {
175
- case "INPUT" :
176
- if ( element . type === "radio" ) {
177
- return this . getRadioButtonValues ( element as HTMLInputElement ) ;
178
- }
170
+ private validate ( elements : Array < HTMLInputElement > ) : Promise < IDynamicKeyValues > {
171
+ return new Promise ( ( resolve ) => {
172
+ let errors = < any > { } ;
173
+ const data = { } ;
174
+ const rule = { } ;
175
+ const customAttributes = { } ;
176
+ let hasAsync : boolean = false ;
179
177
180
- if ( element . type === "checkbox" ) {
181
- return this . getCheckboxValues ( element as HTMLInputElement ) ;
182
- }
178
+ elements . forEach ( element => {
179
+ const name = element . getAttribute ( "name" ) ;
180
+ data [ name ] = this . component . state . fields [ name ] ;
183
181
184
- return element . getAttribute ( "value" ) ;
185
- case "SELECT" :
186
- return ( < HTMLSelectElement > element ) . options [ ( < HTMLSelectElement > element ) . selectedIndex ] . value ;
187
- case "TEXTAREA" :
188
- return element . value ;
189
- default :
190
- return element . getAttribute ( "value" ) ;
191
- }
192
- }
182
+ rule [ name ] = this . rules [ name ] ;
193
183
194
- /**
195
- * Validate the single input element and return validation errors;
196
- *
197
- * @param element HTMLInputElement
198
- */
199
- private validate ( element : HTMLInputElement ) : Promise < IDynamicKeyValues > {
200
- return new Promise ( ( resolve , reject ) => {
201
- const errors = { } ;
202
- const name = element . getAttribute ( "name" ) ;
203
- const data = {
204
- [ name ] : this . getValueFromHtmlNode ( element )
205
- } ;
184
+ if ( ! rule [ name ] ) {
185
+ console . error ( `Rule is not defind for ${ name } ` ) ;
186
+ }
206
187
207
- const rule = { } ;
208
- rule [ name ] = this . rules [ name ] ;
188
+ if ( name . endsWith ( "_confirmation" ) ) {
189
+ const original = name . slice ( 0 , name . indexOf ( "_confirmation" ) ) ;
190
+ data [ original ] = this . component . state . fields [ original ] ;
191
+ }
209
192
210
- if ( ! rule [ name ] ) {
211
- return resolve ( errors ) ;
212
- }
193
+ if ( element . hasAttribute ( "data-attribute- name" ) ) {
194
+ customAttributes [ name ] = element . getAttribute ( "data-attribute-name" ) ;
195
+ }
213
196
214
- const validate = new Validator ( data , rule ) ;
197
+ if ( element . hasAttribute ( "data-async" ) ) {
198
+ hasAsync = true ;
199
+ }
200
+ } ) ;
215
201
216
- if ( element . hasAttribute ( "data-attribute-name" ) ) {
217
- validate . setAttributeNames ( {
218
- [ name ] : element . getAttribute ( "data-attribute-name" )
219
- } ) ;
220
- }
202
+ const validator = new Validator ( data , rule ) ;
203
+ validator . setAttributeNames ( customAttributes ) ;
221
204
222
- if ( element . hasAttribute ( "data-async" ) ) {
205
+ if ( hasAsync ) {
223
206
const passes : Function = ( ) => {
224
- delete this . errors [ name ] ;
207
+ this . invalidateErrors ( data ) ;
225
208
resolve ( errors ) ;
226
209
} ;
227
210
228
211
const fails : Function = ( ) => {
229
- const errMessage : string = validate . errors . first ( name ) ;
230
- errors [ name ] = errMessage ;
212
+ errors = this . fillErrors ( validator ) ;
231
213
resolve ( errors ) ;
232
214
} ;
233
215
234
- validate . checkAsync ( passes , fails ) ;
216
+ validator . checkAsync ( passes , fails ) ;
235
217
return ;
236
218
}
237
219
238
- if ( validate . fails ( ) ) {
239
- const errMessage : string = validate . errors . first ( name ) ;
240
- errors [ name ] = errMessage ;
220
+ if ( validator . fails ( ) ) {
221
+ errors = this . fillErrors ( validator ) ;
241
222
return resolve ( errors ) ;
242
223
}
243
224
244
- delete this . errors [ name ] ;
225
+ this . invalidateErrors ( data ) ;
245
226
return resolve ( errors ) ;
246
227
} ) ;
247
228
}
248
229
230
+ /**
231
+ * Prepare error object to store the errors into the react state.
232
+ *
233
+ * @param validator
234
+ */
235
+ private fillErrors ( validator ) : object {
236
+ const errors = { } ;
237
+ Object . keys ( validator . errors . all ( ) ) . forEach ( field => {
238
+ errors [ field ] = validator . errors . first ( field ) ;
239
+ } ) ;
240
+ return errors ;
241
+ }
242
+
243
+ /**
244
+ * Invalidate valid input field errors.
245
+ *
246
+ * @param data
247
+ */
248
+ private invalidateErrors ( data ) : void {
249
+ Object . keys ( data ) . forEach ( fieldName => {
250
+ delete this . errors [ fieldName ] ;
251
+ } ) ;
252
+ }
253
+
249
254
/**
250
255
* Creating custom event to send form data.
251
256
*
0 commit comments