I'm trying to check if two password fields match and then update a state to true or false based on this. I am using Refs for the input fields and running matchPw on input change.
However the state does not update first time and go out of sync. This is what I have tried:
const matchPw = () => {
let enteredValue = pwOne.current.value;
let enteredRepeatedValue = pwTwo.current.value;
if (enteredValue === enteredRepeatedValue) {
setError((prevState) => ({
...prevState,
pwMatch: true,
}));
console.log("match: " + pwError.pwResetMatchWarning);
} else {
setError((prevState) => ({
...prevState,
pwMatchW: false,
}));
console.log("do not match: " + pwError.pwResetMatchWarning);
}
}
Below, I have mentioned my JS code. So, Kindly suggest or guide me that there is any better approach to implement the validation on form submit for react project or is it right approach which i have implemented already?
submitUserForm = (e) => {
e.preventDefault();
const { formError } = this.state;
let valid = true;
if(document.getElementById('useremail').value === "") {
valid = false;
formError.email = "Kindly enter your email id"
}
else {
valid = true;
formError.email = ""
}
if(document.getElementById('userpassword').value === "") {
valid = false;
formError.password = "Kindly enter the password"
}
else {
valid = true;
formError.password = ""
}
if(valid === true) {
this.formSubmitApi();
}
this.setState({
isValid: valid,
formError
})
}
This is how you can improve your code:
submitUserForm = (e) => {
e.preventDefault();
const formError = {}
if(document.getElementById('useremail').value === "") {
formError.email = "Kindly enter your email id"
}
if(document.getElementById('userpassword').value === "") {
formError.password = "Kindly enter the password"
}
Object.keys(formError).length === 0 && this.formSubmitApi();
this.setState({
formError
})
}
First of all, in order to improve your code, you need to have controlled components (Inputs in this case) in order to store your values in the state and then use them in the submitUserForm function, also, instead of valid variable, I'll use a validation function like (Also, make the useremail and userpassword objects, in order to store the errors there):
state = {
useremail: { value: '', error: '' },
userpassword: { value: '', error: '' },
};
validateValue = value => {
return value !== undefined && value !== null && value !== '';
};
submitUserForm = e => {
const { useremail, userpassword } = this.state;
e.preventDefault();
// If both the 'useremail' and the 'userpassword' pass the 'validateValue' validations, then send the data
if (this.validateValue(useremail.value) && this.validateValue(userpassword.value)) {
this.formSubmitApi(useremail.value, userpassword.value);
// After sending the info, we reset our two states to initial state
this.setState({useremail: { value: '', error: '' }, userpassword: { value: '', error: '' } });
} else {
// If 'useremail' don't pass the validation we store the error
if (!this.validateValue(useremail.value)) {
this.setState({ useremail: { value: useremail.value, error: 'Please enter a valid email' }});
}
// If 'userpassword' don't pass the validation we store the error
if (!this.validateValue(userpassword.value)) {
this.setState({ userpassword: { value: userpassword.value, error: 'Please enter a valid password' }});
}
}
};
I think this is a more clean approach, you only have to states instead of three as before and you can get all the information that you need from those states.
I would change 2 things:
Make the inputs controlled, so that you have better and direct control of the input. Accessing the inputs with document.getElementById is bad practice. Save the text of each input within the state or use refs.
I would change the check for valid input into something like this:
const errors = {};
errors.email = "Kindly enter your email id"
if (Object.keys(errors).length === 0) {...}
It should be a new object, so that you don't mutate the state and this makes it easier because you don't have a second variable.
I hope this helps. Happy coding.
This question already has answers here:
How can I validate an email address in JavaScript?
(79 answers)
Closed 3 years ago.
I'm looking to do a more comprehensive email validation than the one I currently have. If you take a look at my code, I'm only checking for # symbol and ends in .com. Is there a more comprehensive validation check I can include into my current code configuration?
JS:
this.state = {
inputs: {
name: '',
email: '',
message: '',
},
errors: {
name: false,
email: false,
message: false,
},
};
handleOnChange = e => {
const { name, value } = e.target;
if (name === 'email') {
this.setState({
inputs: {
...this.state.inputs,
[name]: value,
},
errors: {
...this.state.errors,
email:
(value.includes('#') && value.slice(-4).includes('.com'))
? false
: true,
},
});
} else {
this.setState({
inputs: {
...this.state.inputs,
[name]: value,
},
errors: {
...this.state.errors,
[name]: false,
},
});
}
};
The best way to validate email is using regular expressions:
const emailRegEx = /^(([^<>()\[\]\.,;:\s#\"]+(\.[^<>()\[\]\.,;:\s#\"]+)*)|(\".+\"))#(([^<>()[\]\.,;:\s#\"]+\.)+[^<>()[\]\.,;:\s#\"]{2,})$/i;
The above will match 99.99% of valid emails
Developing a validation function in React. I fairly new and don't want to develop any bad habits while I'm learning so I'm looking for suggestions on how to clean up a block of code i have here.
The function checks input fields and if they're blank, it attaches the appropriate message to an array. Once all input fields are checked, if that array is empty then proceed to submitting form. If that array contains error messages then the message is displayed to screen (not shown)
validation = (event) => {
event.preventDefault();
let errors = []
const {firstName, lastName, emailAddress, password, confirmPassword} = {...this.state}
if(firstName.length === 0) errors.push('Please provide a value for First Name');
if(lastName.length === 0) errors.push('Please provide a value for Last Name');
if(password.length === 0){
errors.push('Please provide a value for Password');
}else if(password !== confirmPassword){
errors.push('Passwords do not match');
};
if(emailAddress.length === 0) {
errors.push('Please provide a value for Email Address');
}else if(!emailRegex.test(emailAddress)){
errors.push('Invalid email address');
};
this.setState({errors: errors})
if(errors.length === 0) this.logIn()
}
logIn = () => {
console.log('good to go')
};
Just looking for ways to clean up my conditional statements, if possible! Thanks
Perhaps something like the below would suffice. You could simplify this greatly if you provided a generic error message such as "Missing required value: <keyName>", as opposed to something specific for the field.
You'll also want to do a manual check to ensure password === confirmPassword, but I think you'll be able to work that piece out.
const emailRegex = <your regex>;
const hasLength = val => val && val.length !== 0;
Validation Map
const validators = {
firstName: {
validate: hasLength,
message: 'Please provide a value for First Name'
},
lastName: {
validate: hasLength,
message: 'Please provide a value for Last Name'
},
password: {
validate: hasLength,
message: 'Please provide a value for Password'
},
emailAddress: [{
validate: hasLength,
message: 'Please provide a value for Email Address'
},
{
validate: val => !emailRegex.test(val),
message: 'Invalid email address'
}
],
}
Validator
validation = (event) => {
event.preventDefault();
let errors = []
const state = {...this.state};
Object
.keys(state)
.forEach(key => {
let validator = validators[key];
if (!validator) return;
if (!Array.isArray(validator)) {
validator = [validator]
}
validator.forEach(v => {
if (!v.validate(state[key])) {
errors.push(v.message)
}
})
});
this.setState({errors: errors})
if (errors.length === 0) this.logIn()
}
Running into this ReactJS (with Redux) issue:
If premium white isn’t selected, gloss finish should be disabled. The radio button (premium) and checkbox (gloss) have separate methods in separate components – looks like they are both using state to send data.
Here’s the checkbox
buildCheckbox(item) {
return (
<Checkbox
key={item.key}
label={item.display}
name={item.key}
checked={this.props.order[item.key] || false}
onChange={checked => this.handleCheck(checked, item.key)}
disabled={item.disabled(this.props.order)}
/>
);
}
And the handleclick method used
handleCheck(checked, key) {
const { params, updateOrder } = this.props;
const { sessionId } = params;
// if doulbeSided option is removed, then clear the inside file.
if (key === 'doubleSided' && !checked) {
updateOrder(sessionId, { inside: null });
}
// set ink coverage based on printed flag
if (key === 'printed') {
const inkCoverage = checked ? 100 : 0;
updateOrder(sessionId, { inkCoverage });
}
// if unprinted, remove doublesided and gloss options
if (key === 'printed' && !checked) {
updateOrder(sessionId, { doubleSided: false });
updateOrder(sessionId, { gloss: false });
}
updateOrder(sessionId, { [key]: checked });
}
And the radio button’s method
onClick(id, ordAttribute) {
const { updateOrder, sessionId, validator } = this.props;
updateOrder(sessionId, { [ordAttribute]: id });
if (validator) validator(ordAttribute);
}
I saw that gloss has a service which is toggling disabled or not via the printed key on state here
gloss: {
display: 'Gloss Finish',
key: 'gloss',
component: 'checkbox',
disabled: state => !state.printed,
},
I’ve thought about creating a fourth radio button and just deleting the gloss option but I’m not sure where it’s being populated from – also thought about using a display none on the styles of the gloss that is activated via the radio button – but am not sure where to start.
just stated a new job and this is the previous employee's code - trying to figure it out. looks like the state is activated via this Action method:
export const updateOrder = (sessionId, payload) => (dispatch, getState) => {
dispatch(updateAction({ ...payload }));
const state = getState();
const ord = getNewOrderForm(state);
const minOrdValue = getMinOrdValue(state);
const { length, width, height, style, blankLength, blankWidth, qty, leadTime, sqFeet } = ord;
const priceMatrix = style ? getPriceMatrix(state)[style.priceMatrix] : null;
if (priceMatrix && style && style.calcPrice) {
dispatch(dispatchNewPrice(ord, style, priceMatrix, minOrdValue));
}
if (shouldCalcBlank({width, length, height}, style)) {
calcBlanks(style, {width, length, height})
.then(blanks => dispatch(updateAction(blanks)))
.catch(err => console.log('error', err))
}
if (blankLength && blankWidth && qty) {
calcSquareFeet({ blankLength, blankWidth, qty })
.then(sqFeet => {
dispatch(updateAction({ sqFeet }));
return sqFeet;
})
.then(sqFeet => sqFeet > 1000)
.then(lrgSqFeet => {
dispatch(updateAction({ lrgSqFeet }));
return lrgSqFeet;
})
.then(lrgSqFeet => {
if (lrgSqFeet && leadTime === 'rush') {
dispatch(updateAction({ leadTime: 'standard' }));
}
});
}
if (sqFeet && (!blankLength || !blankWidth || !qty)) {
dispatch(updateAction({ sqFeet: 0 }));
}
localStorage.setItem(sessionId, JSON.stringify(getNewOrderForm(getState())));
};
i thought about adding a the radio button has an id of 'clearwater' so i thought about adding a bool to this method that could then be accessed as clearwater: false (and when onClick is activated, updateOrder then changes it to clearwater: true, and then the gloss object in the service would then check disabled: state => !state.printed && !state.clearwater (this didn't work):
export const generateNewOrder = (userid, style, sessionId = uuid()) => dispatch => {
localStorage.setItem(
sessionId,
JSON.stringify({
userid,
style,
sessionId,
blindShip: true,
inkCoverage: '100',
printed: true,
})
);
history.push(`/order/new/${style.styleCode}/${sessionId}`);
dispatch(
newOrder({
userid,
style,
sessionId,
blindShip: true,
inkCoverage: '100',
printed: true,
})
);
if (style.type === 'static') {
const { dims, blankLength, blankWidth } = style;
const payload = {
...dims,
blankLength,
blankWidth,
};
dispatch(updateOrder(sessionId, payload));
}
};
I was hoping by changing the Service attached to the checkbox, I could add an additional condition that would cause the disabled functionality to be dependent on the state.boardStyle, but this doesn't seem to work (picture below isn't accurate, i changed it to boardStyle):
http://oi65.tinypic.com/wknzls.jpg
This is using redux -- kind of new to redux -- let me know if I'm missing any info -- I will post anything to get this solved.
Any help would be huge – thanks so much!
i think i figured it out . . .
there's probably a drier way to do this, but here goes:
first i created a new key [bool] (clearwater, set to false) on generateNewOrder method in Actions:
export const generateNewOrder = (userid, style, sessionId = uuid()) => dispatch => {
localStorage.setItem(
sessionId,
JSON.stringify({
userid,
style,
sessionId,
blindShip: true,
inkCoverage: '100',
printed: true,
clearwater: false,
})
);
history.push(`/order/new/${style.styleCode}/${sessionId}`);
dispatch(
newOrder({
userid,
style,
sessionId,
blindShip: true,
inkCoverage: '100',
printed: true,
clearwater: false
})
);
if (style.type === 'static') {
const { dims, blankLength, blankWidth } = style;
const payload = {
...dims,
blankLength,
blankWidth,
};
dispatch(updateOrder(sessionId, payload));
}
};
that gave me access to this state value, which i could then use in the onclick when the radio button was pressed. if the id was clearwater, the bool would be set to true, else it was set to false (only for the other two options because this code is used for other IDs)
onClick(id, ordAttribute) {
const { updateOrder, sessionId, validator } = this.props;
updateOrder(sessionId, { [ordAttribute]: id });
if (validator) validator(ordAttribute);
if (id === 'clearwater') {
updateOrder(sessionId, { clearwater: true });
} else if (id === 'kraft' || id === 'std_white_two_side'){
updateOrder(sessionId, { clearwater: false });
}
}
then all i needed to do was add this to the Service. if it was not printed !printed or not clearwater !clearwater, the checkbox would be disabled
const printing = {
doubleSided: {
display: 'Two Sided Print',
key: 'doubleSided',
component: 'checkbox',
disabled: state => !state.printed,
},
printed: {
display: 'Printed?',
key: 'printed',
component: 'checkbox',
disabled: () => false,
},
gloss: {
display: 'Gloss Finish',
key: 'gloss',
component: 'checkbox',
disabled: state => !state.printed || !state.clearwater,
},
};
I have a working example answering a similar problem, please, have a look. The whole logic is done in redux:
Want to uncheck the node of the tree structure in React JS