Skip to content

Commit 6a3a7a5

Browse files
committed
🐛 Confirm password validation not working issue fixed
Issue ID: #19 Code changes, 1) Fixed confirm password not working issue 2) Reduced the package size with webpack configurations. 3) Performance optimization Signed-off-by: gokulakannant <[email protected]>
1 parent 2df312c commit 6a3a7a5

File tree

2 files changed

+85
-75
lines changed

2 files changed

+85
-75
lines changed

src/index.ts

Lines changed: 78 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*

webpack.config.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,24 @@ const path = require('path');
22
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
33

44
module.exports = {
5-
entry: './src/index.ts',
5+
entry: {
6+
bundle: './src/index.ts'
7+
},
68
module: {
79
rules: [
810
{ test: /\.ts(x?)$/,
911
use: 'ts-loader'
1012
}
1113
]
1214
},
15+
externals : {
16+
validatorjs: 'validatorjs'
17+
},
1318
resolve: {
1419
extensions: [ '.tsx', '.ts', '.js', '.css' ]
1520
},
1621
output: {
17-
filename: 'bundle.js',
22+
filename: "[name].js",
1823
path: path.resolve(__dirname, 'dist'),
1924
libraryTarget: 'umd'
2025
},

0 commit comments

Comments
 (0)