Disable button until all form inputs are validated in React - javascript

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.

Related

State not changing after update

I have a problem with use state component of property where the state does not change when loading component. The state of the item should change since i am updating it after receiving a response in the previous form stepper but when i add a new dynamic input field, it changes the state but not for the first one
Here is the code that is bringing the error
export default function AddProp() {
const [propertyID, setPropertyID] = useState(0);
const [step,setStep] = useState(1);
const [values,setValues] = useState({
responseMessage: "",
loading: false,
name: "",
address: "",
county: "",
city: "",
zipcode: "",
type: "",
specifictype: "",})
const [formValues, setFormValues] = useState([
{ number_of_units: "", market_rent: "", square_feet: "", beds: "", property:propertyID.property },
])
let addFormFields = () => {
setFormValues([
...formValues,
{ number_of_units: "", market_rent: "", square_feet: "", beds: "" ,property:propertyID.property},
]);
};
let sendProperties = async () => {
const response = await axios
.post(
"http://127.0.0.1:8000/property/api/v1/addProperty/",
{
property_name: values.name,
address: values.address,
county: values.county,
city: values.city,
zipcode: values.zipcode,
property_type: values.type,
},
{ headers: headers }
);
setPropertyID(response.data);
if(response.status == 200){
setStep(step + 1 );
}else{
alert("An error occurred");
}
};
switch (step) {
case 3:
return (
<PropertyType
values={formValues}
handleChange={handleFormChange}
add={addFormFields}
remove={removeFormFields}
prevStep={prevStep}
nextStep={getandSend}
/>
);
case 4:
return <Success message={"DONE"} />;
default:
}
}
Instead of using the current formValues, pass a callback to setFormValues that takes in one parameter, say currentFormValues, and use that to update the state instead.
const addFormFields = () => {
setFormValues(currentFormValues => [
...currentFormValues,
{ number_of_units: "", market_rent: "", square_feet: "", beds: "" ,property:propertyID.property},
]);
};
This problem is related to stale state, a problem that occurs whenever we're trying to update state, often within a closure.

Validation continues when input value is deleted

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: '' });
}
};

PhoneInput value display in data preview in React

I'm trying to display PhoneInput value in a data preview (React) using an event handler handleOnChangePhoneInput. How do I make it work?
Here is the source code.
I want to display the "phone number" value entered by a user in the "data preview" sheet right below the "Submit" button in the demo. For example, when one enters a "first name" value and click on "Submit", the first name is displayed in the data preview but I could not make it work for "phone number" and "data of birth".
Demo
Component
<PhoneInput
name="phoneNumber"
type="text"
country={"us"}
enableAreaCodes={true}
onlyCountries={["us"]}
areaCodes={{ us: ["000"] }}
inputProps={{
name: "phone",
country: "us",
required: true,
autoFocus: true
}}
value={this.state.phone}
onChange={this.handleOnChangePhoneInput}
inputStyle={{
width: "230px",
height: "45px"
}}
/>
Event
handleOnChangePhoneInput = value => {
this.setState({ phone: value }, () => {
return this.state.phone;
});
};
[Thanks! I'm new to React.]
So this is how you would do it , First of all you need to maintain the state of your inputs so you would have to modify the state a bit
state = {
firstName: "",
lastName: "",
phone: "",
emailAddress: "",
eligibleAge: false,
max: new Date(
new Date().getFullYear() - 21,
new Date().getMonth(),
new Date().getDate()
),
min: new Date(
new Date().getFullYear() - 120,
new Date().getMonth(),
new Date().getDate()
),
selectedDate: ""
};
the next thing you want to do is create three additional event listeners one for all the text inputs and one for the checkbox and one for the calender, this could be merged into one but for simplicity let's keep it separate
// Text Inputs
onChange = e => {
console.log(e);
this.setState(
{
...this.state,
[e.fieldProps.name]: e.fieldProps.value
},
() => {
console.log(this.state);
}
);
};
// CheckBox
onCheckBoxChange = e => {
this.setState(
{
...this.state,
eligibleAge: !this.state.eligibleAge
},
() => {
console.log(this.state);
}
);
};
// Calender
onSelect = e => {
var SelectedDate =
e.getDate() + "-" + (e.getMonth() + 1) + "-" + e.getFullYear();
this.setState(
{
...this.state,
selectedDate: SelectedDate
},
() => {
console.log(this.state);
}
);
};
the next thing you want to do is pass the arguments to the function.(since in the demo that you provided if a filed is empty it does not show.so i decided to mimic that by checking if that field is empty)
<Form
onSubmitStart={() =>
this.props.onSubmitStart({
...(this.state.firstName !== "" && {
firstName: this.state.firstName
}),
...(this.state.lastName !== "" && {
lastName: this.state.lastName
}),
...(this.state.emailAddress !== "" && {
emailAddress: this.state.emailAddress
}),
...(this.state.phone !== "" && { phone: this.state.phone }),
selectedDate: this.state.selectedDate,
eligibleAge: this.state.eligibleAge
})
}
>
and in the parent component(index.js) you would just change
handleSubmitStart = ({serialized}) => {
to this:
handleSubmitStart = serialized => {
CodeSandbox : here
your handle function must be something like:
const handleOnChangePhoneInput = value => {
this.setState({ phone: value });
};
and then, if you want to show the value make an onClick function inside the submit button
like:
const handleOnSubmit=()=>{
this.setState({visibleTelephone:true})
}
and in your component you need to add where is going to show the value:
<div>
{this.state.visibleTelephone?this.state.phone:null}
</div>

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,
},
});
}
};

How to fix Invalid destructuring assignment target?

What I can do in order to fix my problem? I'm a new newbie in javascript and any recomendations or advices could be helpful to me.
var user = {
username: "Andrey",
password: "JavaScript"
},
{
username: "Max",
password: "12345"
},
{
username: "Pasha",
password: "OWL"
};
var database = [user];
var newsfeed = [
{
username: "Bobby",
timeline: "DOOOOOOG!",
},
{
username: "Max",
timeline: "CAAAAT!",
},
{
username: "Lida",
timeline: "John Ceeeenaaaa!",
}
];
var userNamePrompt = prompt("Your Username?");
var passwordPrompt = prompt("Your password?");
function isUserValid(Name, Pass){
for (var i=0; i<database.length; i++){
if (database[i].username === Name &&
database[i].password === Pass) {
return true;
}
}
return false;
}
function SignIn (Name, Pass){
if (isUserValid(Name, Pass)) {
console.log(newsfeed);
}
else {
alert("Sorry smt went wrong!");
}
}
SignIn (userNamePrompt, passwordPrompt);
If the code is working correctly, i should get back an array with a newsfeed, but instead im getting:
Invalid destructuring assignment target
You wrote: var user = { property }{ property }{ property } which doesn't work. This is probably what you meant ( also skips the var database = [ user ]; assignment):
var database = [
{
username: "Andrey",
password: "JavaScript"
},
{
username: "Max",
password: "12345"
},
{
username: "Pasha",
password: "OWL"
};
]

Categories