@@ -85,7 +85,7 @@ class ReactFormInputValidation extends BaseValidation {
8585
8686 public handleBlurEvent ( event : React . FocusEvent < HTMLInputElement > ) {
8787 const element : HTMLInputElement = event . target ;
88- this . validate ( element ) . then ( ( inputErrors ) => {
88+ this . validate ( [ element ] ) . then ( ( inputErrors ) => {
8989 if ( this . component && this . component . hasOwnProperty ( "state" ) ) {
9090 this . errors = Object . assign ( this . errors , inputErrors ) ;
9191 this . component . setState ( { errors : this . errors , isValidatorUpdate : true } ) ;
@@ -114,32 +114,29 @@ class ReactFormInputValidation extends BaseValidation {
114114 } ;
115115 }
116116
117- const validatePromises : Array < Promise < any > > = [ ] ;
117+ const elements = [ ] ;
118118
119119 form . querySelectorAll ( "textarea,select,input:not([type='submit']):not([type='file']):not([data-ignore-validation])" )
120120 . forEach ( ( element ) => {
121- validatePromises . push ( this . validate ( element ) ) ;
121+ elements . push ( element ) ;
122122 } ) ;
123123
124124 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 ) ) ;
143140 } ) ;
144141 }
145142
@@ -166,86 +163,94 @@ class ReactFormInputValidation extends BaseValidation {
166163 }
167164
168165 /**
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;
170167 *
171- * @param element HTMLInputElement or HTMLSelectElement
168+ * @param element HTMLInputElement
172169 */
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 ;
179177
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 ] ;
183181
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 ] ;
193183
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+ }
206187
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+ }
209192
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+ }
213196
214- const validate = new Validator ( data , rule ) ;
197+ if ( element . hasAttribute ( "data-async" ) ) {
198+ hasAsync = true ;
199+ }
200+ } ) ;
215201
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 ) ;
221204
222- if ( element . hasAttribute ( "data-async" ) ) {
205+ if ( hasAsync ) {
223206 const passes : Function = ( ) => {
224- delete this . errors [ name ] ;
207+ this . invalidateErrors ( data ) ;
225208 resolve ( errors ) ;
226209 } ;
227210
228211 const fails : Function = ( ) => {
229- const errMessage : string = validate . errors . first ( name ) ;
230- errors [ name ] = errMessage ;
212+ errors = this . fillErrors ( validator ) ;
231213 resolve ( errors ) ;
232214 } ;
233215
234- validate . checkAsync ( passes , fails ) ;
216+ validator . checkAsync ( passes , fails ) ;
235217 return ;
236218 }
237219
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 ) ;
241222 return resolve ( errors ) ;
242223 }
243224
244- delete this . errors [ name ] ;
225+ this . invalidateErrors ( data ) ;
245226 return resolve ( errors ) ;
246227 } ) ;
247228 }
248229
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+
249254 /**
250255 * Creating custom event to send form data.
251256 *
0 commit comments