Validation continues when input value is deleted - javascript

There are validations for mandatory input fields. Validation works when these fields are unfilled or filled incorrectly. After filling the field I delete it but the validation still works and an error message pops up. I don't want validation to run when input value is deleted.
How can I solve it?
js
const [nameValidationState, setNameValidationState] = useState({
error: false,
helperText: '',
});
const nameOnChange = (event) => {
if (nameValidator(event.target.value)) {
setNameValidationState({ error: false, helperText: '' });
setPaymentInfo({
...paymentInfo,
firstName: event.target.value,
});
} else {
setNameValidationState({ error: true, helperText: 'Please enter your name.' });
setPaymentInfo({
...paymentInfo,
firstName: null,
});
}
};
const handleInputChange = (event) => {
const { name, value } = event.target;
setPaymentInfo({ ...paymentInfo, [name]: value });
};
const handleFirstNameChange = (event) => {
nameOnChange(event);
handleInputChange(event);
};
html
<AS.TextField
id="outlined-basic"
label={t('general.name')}
variant="outlined"
sx={{ width: '100%', maxWidth: '500px', margin: 'auto' }}
InputLabelProps={{
shrink: true,
}}
placeholder=""
onChange={handleFirstNameChange}
error={nameValidationState.error}
helperText={nameValidationState.helperText}
name="firstName"
value={paymentInfo.firstName}
/>
<AS.TextField
validator.js
export const nameValidator = (name) => {
const nameRegex = /^[a-zA-ZwığüşöçĞÜŞÖÇİ]+$/;
return nameRegex.test(name);
};

Changing the nameOnChange method like this will solve the problem.
const nameOnChange = (event) => {
if (nameValidator(event.target.value)) {
setNameValidationState({ error: false, helperText: '' });
setPaymentInfo({
...paymentInfo,
firstName: event.target.value,
});
} else {
setNameValidationState({ error: true, helperText: 'Please enter your name.' });
setPaymentInfo({
...paymentInfo,
firstName: null,
});
}
if (event.target.value === '') {
setNameValidationState({ error: false, helperText: '' });
}
};

Related

Disable button until all form inputs are validated in React

I have this form in my code, I want to, after checking all validation and patterns, the form button to become enabled, but I don't know how I can put this in my form, or do I need to write any other functions and which way is most clean Code?
const [disable, setDisable] = React.useState(true);
const [staff, setStaff] = React.useState({
username: "",
email: "",
phone: "",
password: "",
});
const [errMessage, setErrMessage] = React.useState({
username: "",
email: "",
phone: "",
password: "",
});
const handleChange = (e) => {
switch (e.target.name) {
case "email": {
if (e.target.value.toLowerCase().match(emailValidation)) {
setErrMessage({ ...errMessage, email: "" });
setStaff({ ...staff, email: e.target.value });
} else {
setErrMessage({
...errMessage,
email: "It should be a valid email address",
});
}
}
case "password": {
if (e.target.value.length >= 12) {
setErrMessage({ ...errMessage, password: "" });
setStaff({ ...staff, password: e.target.value });
} else {
setErrMessage({
...errMessage,
password: "It should be at least 12 character",
});
}
}
default:
setStaff({
...staff,
[e.target.name]: e.target.value,
});
}
};
return( <button disabled={disable}>Submit</button>)
Since you are tracking the errors in that errMessage state, you don't need an additional state for disable. It could be a simple constant you can add above and outside handleChange:
const disable =
Object.values(errMessage).filter((v) => v).length > 0 ||
Object.values(staff).filter((v) => v).length !== 4;
<button disabled={disable}>Submit</button>
This way, the button is disabled when there is an error message, or when one field is empty.

React useState not updating all property except when using loops

I am validating form from server side. once I get error message, I wants to show error message on respective textbox field's error message
client side Object
const formFields = {
firstName: {
helperText: '',
error: false
},
lastName: {
helperText: '',
error: false
},
emailID: {
helperText: '',
error: false
},
phoneNo: {
helperText: '',
error: false
},
password: {
helperText: '',
error: false
},
confirmPassword: {
helperText: '',
error: false
}
}
Server side response object after validation
const responseError = errorData.response.data.errors //below object is the response
//{
//"LastName": ["Enter LastName"],
//"FirstName": ["Enter FirstName"],
//"ConfirmPassword": ["Enter Confirm Password","confirm password do not match"]
//}
useState
const [inpValues, setInpValues] = useState(formFields)
Conditions to update
if ClientSideObj.key === responseObj.key then setInpValues of error and helperText field
const responseError = errorData.response.data.errors
console.log(responseError)
var FormFieldName = ""
for (keys in formFields) {
console.log('FormField keys = ' + keys)
for (var errorKeys in responseError) {
if (keys.toLowerCase() === errorKeys.toLowerCase()) {
console.log('* MATCHED FIELDS = ' + errorKeys)
//Matched 3 fields(LastName,FirstName,ConfirmPassword) successfully
FormFieldName = keys
setInpValues(prevInpValues => ({
...prevInpValues,
[FormFieldName]: {
...prevInpValues[FormFieldName],
error: true,
helperText: responseError[errorKeys]
}
})
)
console.table(inpValues)
}
}
}
Note
I go through this stack overflow already, then I passed previousState values also. still result same.
It's updating only the last for loop condition value
If the response.error object has return only one field, then it's updating that one
It's updating only the last for loop condition value
Javascript infamous Loop issue?
What is the difference between "let" and "var"?
as Miguel Hidalgo states, you should make all changes in one update:
const responseError = errorData.response.data.errors
console.log(responseError)
setInpValues(state => {
const newState = { ...state };
for (let errorKey in responseError) {
for (let formField in formFields) {
// this would be so much simpler if your properties would be in the correct case and you'd not have to do this dance with `.toLowerCase()`
if (formField.toLowerCase() !== errorKey.toLowerCase()) {
continue;
}
newState[formField] = {
...newState[formField],
error: true,
helperText
}
}
}
return newState
});
If errorKey and fieldName would be identical and you'd not have to match them case insensitive you could write this:
const responseError = errorData.response.data.errors
console.log(responseError)
setInpValues(state => {
const newState = { ...state };
for (let formField in responseError) {
newState[formField] = {
...newState[formField],
error: true,
helperText: responseError[formField]
}
}
return newState
});
What you should do in order to avoid unnecessary extra renders its to loop inside setState callback:
setInpValues(prevInpValues => {
for (const formKey in formFields) {
for (const errorKey in responseError) {
if (formKey.toLowerCase() === errorKey.toLowerCase()) {
prevInpValues[formKey] = {
...prevInpValues[formKey],
error: true,
helperText: responseError[errorKey]
}
}
}
}
return {...prevInpValues}
}

RegExp for email validation is not reading string properly (using React, no JSX)

I am trying to get my "submit" button to be enabled or disabled based on the validity of the email that is passed. However, the RegExp expression I am using is not reading the string properly. I've tried testing my isWorking() function with just email.length > 0 to make sure that whatever is being passed to isWorking() is indeed a string, and we are good there but RegExp is always returning false regardless of the input it receives. I'm using React without JSX in this app. Any help at all would be deeply appreciated. Thank you so much!
const validEmailRegex = RegExp(/^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
class Signup extends React.Component {
constructor() {
super();
this.state = {
email: ""
};
this.handleSubmit = this.handleSubmit.bind(this);
}
isWorking () {
const email = event.target;
//if (email.length > 0) {
// return false;
// }
// return true;
if (validEmailRegex.test(email) === true) {
return false;
}
return true;
}
handleSubmit(event) {
event.preventDefault();
if (!event.target.checkValidity()) {
this.setState({
invalid: true,
displayErrors: true,
});
return;
}
const form = event.target;
const data = new FormData(form);
for (let name of data.keys()) {
const input = form.elements[name];
const parserName = input.dataset.parse;
console.log('parser name is', parserName);
if (parserName) {
const parsedValue = inputParsers[parserName](data.get(name));
data.set(name, parsedValue);
}
}
this.setState({
res: stringifyFormData(data),
invalid: false,
displayErrors: false,
});
}
render() {
const { res, invalid, displayErrors } = this.state;
//pass data to the button for disabling or not
const isEnabled = this.isWorking();
return (
React.createElement("div", { className: "container" },
React.createElement("div", { className: "row" },
React.createElement("form", { onSubmit: this.handleSubmit, noValidate: true, className: displayErrors ? 'displayErrors' : '' },
React.createElement("input", { className: "form-control", name: "formEmail", id: "formEmail", type: "email", placeholder: "email"}),
),
React.createElement("span", { className: "span"},
React.createElement("fieldset", { className: "form-group" },
React.createElement(Link, { className: "nav-link", activeClassName: "nav-link-active", to: "/contact" },
React.createElement("button", { className: "button1", disabled: isEnabled, type: "button"}, "next")
),
)
),
),
)
);
}
}
Your isWorking() does not receive event from anywhere. Also, event.target will be an HTML element and definitely not an input value. For a form, you do event.target.elements["<name_of_input>"] (here, name of input if formEmail) to get input value.

Email Input Warning - A component is changing a controlled input of type text to be uncontrolled

In my React app, I'm getting this error during onChange event with my email input field:
Warning: A component is changing a controlled input of
type text to be uncontrolled. Input elements should not switch from
controlled to uncontrolled (or vice versa).
Here's the onChange block that's causing this warning; The error goes away if I remove the first if block but of course I need it there for email validation.
validateEmail(email) {
const re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
handleOnChange = e => {
const { name, value } = e.target;
const emailInput = e.target.value;
const emailValid = this.validateEmail(emailInput);
if (name === 'email') {
this.setState({
inputs: {
email: emailInput,
},
errors: {
email: !emailValid,
},
});
} else {
this.setState({
inputs: {
...this.state.inputs,
[name]: value,
},
errors: {
...this.state.errors,
[name]: false,
},
});
}
};
State:
constructor() {
super();
this.state = {
inputs: {
name: '',
email: '',
message: '',
},
phone: '',
show: true,
errors: {
name: false,
email: false,
message: false,
},
};
}
How do I keep my current code and address the warning?
You need to spread the existing/previous state in the if-block. You likely have other input tags that were initially connected to the input-state object which looks like:
inputs: {
name: "",
email: "",
message: ""
}
<input value={this.state.input.name} name="name"/>
<input value={this.state.input.email} name="email"/>
<input value={this.state.input.message} name="message"/>
but when you used this.setState() in your posted code, the connection is lost. You are setting the inputs state to an object with a single property of email:
inputs: {
email: "valueFromEventTarget"
}
What you need to do is spread the existing state so you don't lose the other key/value pairs in the input object: Update your handleChange() function to this:
handleOnChange = e => {
const { name, value } = e.target;
const emailInput = e.target.value;
const emailValid = this.validateEmail(emailInput);
if (name === 'email') {
this.setState({
inputs: {
...this.state.inputs,
email: emailInput,
},
errors: {
...this.state.errors,
email: !emailValid,
},
});
} else {
this.setState({
inputs: {
...this.state.inputs,
[name]: value,
},
errors: {
...this.state.errors,
[name]: false,
},
});
}
};

Boolean State Value Changes to Undefined on Second onSubmit

I'm working on a React project and implementing email validation and setting the state to true when it doesn't pass and false when it does. Validation part works, but getting undefined state on second onSubmit.
A bit more detail: I'm checking the state onChange and onSubmit. onChange seems to work as expected. onSubmit does work on the first click/submit but the very next click/submit, it changes the state to 'undefined' and I have no idea why.
Best to view my codepen and start filling in the email field and checking the console as I'm logging the state.
Here's a snippet of the code:
this.state = {
inputs: {
name: '',
email: '',
message: '',
},
show: true,
errors: {
name: false,
email: false,
message: false,
},
};
validateEmail(email) {
const re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
handleOnChange = e => {
const { name, value } = e.target;
const emailInput = e.target.value;
const emailValid = this.validateEmail(emailInput);
if (name === 'email') {
this.setState({
inputs: {
email: emailInput,
},
errors: {
email: !emailValid,
},
});
} else {
this.setState({
inputs: {
...this.state.inputs,
[name]: value,
},
errors: {
...this.state.errors,
[name]: false,
},
});
}
console.log('errors.email onChange = ' + this.state.errors.email);
};
So, why is this happening? and how can I solve?
You have missed the else condition when the field is not empty. that will remove the error object key from state, that is the one gives you the undefined error.
rewrite the handleSubmit function like this.
handleSubmit = (e, slackPost) => {
e.preventDefault();
console.log('errors.email onClick = ' + this.state.errors.email);
let inputFields = document.getElementsByClassName('form-input');
let invalidEmailMessage = document.querySelector('#invalid-email-message');
let failMessage = document.querySelector('#fail-message');
let failMessageBox = document.querySelector('.alert-fail');
// empty array to house empty field names
const emptyFieldNames = [];
// empty object to house input state
let errors = {};
// loop through input fields...
for (var i = 0; i < inputFields.length; i++) {
if (inputFields[i].value === '') {
let inputName = inputFields[i].name;
// add name to new array
emptyFieldNames.push(inputFields[i].getAttribute('name'));
// add input name and value of true to new object
errors[inputName] = true;
failMessageBox.style.display = 'block';
} else {
let inputName = inputFields[i].name;
errors[inputName] = false;
}
}
debugger;
this.setState({ errors });
if (emptyFieldNames.length > 0) {
failMessage.innerHTML =
'Please complete the following field(s): ' + emptyFieldNames.join(', ');
} else if (this.state.errors.email === true) {
invalidEmailMessage.innerHTML = 'Please enter a valid email';
} else {
console.log('For Submitted!');
}
};

Categories