How to show Inputs Values in Object in React - javascript

I try to show all data onChange inputs in Object to post it in API in React and I tried the following:
import React, { useState} from "react";
const Counter = () => {
const [form, setForm] = useState({});
const FormData = (event, {name, value}) => {
setForm({...form, [name]: value});
};
return (
<div>
<input value={form.username || ''} name="username" onChange={FormData} type="text"/>
<input value={form.email || ''} name="email" onChange={FormData} type="email"/>
<input value={form.password || ''} name="password" onChange={FormData} type="password"/>
</div>
);
}
export default Counter;
But it shows issue onChange : "Cannot destructure property 'name' of 'undefined' as it is undefined"

It can be done as follows:
const Counter = () => {
const [form, setForm] = useState({});
const FormData = (event) => {
const { target: { value, name } } = event;
setForm({...form, [name]: value});
};
return (
<div>
<input value={form.username || ''} name="username" onChange={FormData} type="text"/>
// same for other inputs
</div>
);
}

Related

react input form returns undefined

it updates only the lastly typed input box value in the state and other are undefined
i get this in console
Object { Name: undefined, Age: "123", City: undefined }
second time
Object { Name: undefined, Age: undefined, City: "city" }
Form.jsx
import React, {useState} from 'react';
const Form = (props) => {
const [formData, setFormData] = useState({ Name:'', Age:'', City:''});
const infoChange = e => {
const { name,value} = e.target;
setFormData({
[e.target.name]: e.target.value,
})
}
const infoSubmit = e =>{
e.preventDefault();
let data={
Name:formData.Name,
Age:formData.Age,
City:formData.City
}
props.myData(data);
}
return (
<div className="">
<form onSubmit={infoSubmit} autoComplete="off">
<div className="form-group mb-6">
<label className="">Name:</label>
<input type="text" onChange={infoChange} name="Name" value={formData.Name} className=""placeholder="Enter Name" />
</div>
<div className="form-group mb-6">
<label className="">City:</label>
<input type="text" onChange={infoChange} name="City" value={formData.City} className=""
placeholder="Enter Age" />
</div>
<button type="submit" className="">Submit</button>
</form>
</div>
);
};
export default Form;
App.jsx
this is App.jsx file, here i get the data prop and display it in console.log
import React from 'react';
import Form from './components/Form';
import Table from './components/Table';
const App = () => {
const create = (data) => {
console.log(data);
}
return (
<div className='flex w-full'>
<div className=''>
<Form myData={create} />
</div>
<div className=''>
<Table />
</div>
</div>
);
};
export default App;
You're stomping the previous state with the most recent change. If you want to preserve the existing state you have to include it in the update.
setFormData({
...formData,
[e.target.name]: e.target.value,
})
with react-hooks you need to set the entire object again.
const [formData, setFormData] = useState({ Name:'', Age:'', City:''});
const infoChange = e => {
const { name,value} = e.target;
setFormData({
// spread the current values here
...formData,
// update the current changed input
[name]: value,
})
or, even better IMHO. You have one state for each prop
const [name, setName] = useState('');
const [age, setAge] = useState('');
const [city, setCity] = useState('');
// ...
<input onChange={({target: {value}}) => setName(value)} />
<input onChange={({target: {value}}) => setAge(value)} />
<input onChange={({target: {value}}) => setCity(value)} />
Change this
const infoChange = e => {
const { name,value} = e.target;
setFormData({...formData
[e.target.name]: e.target.value,
})
}

Disable and enable button after checking some condition

I have this button here
<button className={Classes.Button}
disabled={!isEnabled}
type="submit">
{buttonText}
</button>
which should be disabled or enable after checking the value of some of my inputs.
the conditions
const canBeSubmitted = () => {
return (
customerData.firstNameState.length > 0 && // TextInput
customerData.emailState.length > 0 && // TextInput
customerData.companeyState.length > 0 && // TextInput
customerData.selected.length > 0 && // Dropdown
customerData.agree === true // checkbox for terms
);
};
let isEnabled = canBeSubmitted();
BTW: The agree checkbox is checked by its handler and works fine.
The agree value is false in the state and the handler
const handleChange = (event) => {
const field = event.target.id;
if (field === "firstName") {
setFirstName({ firstName: event.target.value });
} else if (field === "email") {
setEmail({ email: event.target.value });
} else if (field === "country") {
setSelected({ country: event.target.value });
} else if (field === "agree") {
setAgree(!agree);
console.log(agree);
}
};
but always return false. what am I missing?
Please help me out
If I'm correct, your 'state' isn't changing because of how you're changing 'state variables' in handleChange fat arrow function.
I could be wrong depending on how your 'state' is structured.
I'm assuming your 'state' is structured like this.
const [firstName, setFirstName] = useState("");
const [email, setEmail] = useState("");
const [country, setCountry] = useState("");
const [agree, setAgree] = useState(false);
Fix your handleChange function.
// Commented out your possibly erroneous code.
const handleChange = (event) => {
const field = event.target.id;
if (field === "firstName") {
// Fix here.
// setFirstName({ firstName: event.target.value }); ❌
setFirstName(event.target.value); ✅
} else if (field === "email") {
// Fix here.
// setEmail({ email: event.target.value }); ❌
setEmail(event.target.value); ✅
} else if (field === "country") {
// Fix here.
// setSelected({ country: event.target.value }); ❌
setCountry(event.target.value); ✅
} else if (field === "agree") {
// Fix here.
// setAgree(!agree); ❌
setAgree(event.target.checked); ✅
console.log(agree);
}
};
You can then perform your validation like this:
const canBeSubmitted = () => {
return (
firstName.trim().length && // TextInput
email.trim().length && // TextInput
country.trim().length && // Dropdown
agree // checkbox for terms
);
};
It appears your also have a typo here for 'countryState':
customerData.companeyState.length > 0 && // TextInput
It looks like there is a full stop after && operator in your code.
customerData.selected.length > 0 &&. // Dropdown
Addendum
#Harry9345, you can as well get rid of the handleChange completely.
Full source code below. Demo: https://codesandbox.io/s/crimson-fog-vp19s?file=/src/App.js
import { useEffect, useState } from "react";
export default function App() {
const [firstName, setFirstName] = useState("");
const [email, setEmail] = useState("");
const [country, setCountry] = useState("");
const [agree, setAgree] = useState(false);
const canBeSubmitted = () => {
const isValid =
firstName.trim().length && // TextInput
email.trim().length && // TextInput
country.trim().length && // Dropdown
agree; // checkbox for terms
if (isValid) {
document.getElementById("submitButton").removeAttribute("disabled");
} else {
document.getElementById("submitButton").setAttribute("disabled", true);
}
console.log({ firstName, email, country, agree });
};
useEffect(() => canBeSubmitted());
return (
<div>
<form action="" method="post" id="form">
<label htmlFor="firstName">First name:</label>
<br />
<input
type="text"
id="firstName"
name="firstName"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
<br />
<label htmlFor="email">Email Address:</label>
<br />
<input
type="email"
id="email"
name="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<br />
<label htmlFor="country">Choose a country:</label>
<br />
<select
id="country"
name="country"
value={country}
onChange={(e) => setCountry(e.target.value)}
>
<option value="">Select..</option>
<option value="1">USA</option>
<option value="2">Canada</option>
<option value="3">Algeria</option>
</select>
<br />
<input
type="checkbox"
name="agree"
id="agree"
onClick={(e) => setAgree(e.target.checked)}
/>
<label htmlFor="agree"> I agree.</label>
<br />
<button type="submit" id="submitButton">
Submit
</button>
</form>
</div>
);
}
You should use state instead of variable:
I added some example:
import { useState } from "react";
const App = () => {
const [isDisabled, setIsDisabled] = useState(true);
const [checked, setChecked] = useState(false);
const canBeSubmitted = () => {
return checked ? setIsDisabled(true) : setIsDisabled(false);
};
const onCheckboxClick = () => {
setChecked(!checked);
return canBeSubmitted();
};
return (
<div className="App">
<input type="checkbox" onClick={onCheckboxClick} />
<button type="submit" disabled={isDisabled}>
Submit
</button>
</div>
);
};
export default App;
codesandbox
Of course it's just a sample of code and not very efficient.

how to conditionally render the respond from an api

I want to get input from a user and compare it with the response I am getting from API, and conditionally render the information if it match or just show a sorry message,(the API only contain 1 set of a data object including 4 value) let me know what am I missing.
here is my code
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatInput, setVatInput] = useState("");
const [responseVatState, setResponseVatState] = useState("");
const [responseCountryCodeState, setResponseCountryCodeState] = useState("");
const [result, setResult] = useState(false);
const handelVatState = (event) => {
setVatInput(event.target.value);
};
const closeModalHandler = () => {
setResult(false);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("Some URL")
.then((response) => {
setResponseVatState(response.data.response.data.VATNumber);
setResponseCountryCodeState(response.data.CountryCode);
})
.catch((error) => {
console.log(error);
});
};
const inputCountryCode = vatInput.substring(0, 2);
const inputVatCode = vatInput.substring(2);
if (
inputCountryCode === responseCountryCodeState &&
inputVatCode === responseVatState
) {
setResult(true);
} else {
setResult(false);
}
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
<label className="text-muted">Result : </label>
{result ? (
<div>{vatInput}</div>
) : (
<div clicked={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
)}
</div>
);
}
export default Form;
and the error is
react-dom.development.js:14997 Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
so I get the input from the user and set it with hooks, then with Axios call get my data, then I split the string with
const inputCountryCode = vatInput.substring(0, 2);
const inputVatCode = vatInput.substring(2);
to compare with the input I have, if it's the same then render the data if not just render the sorry message
You have a couple of issues, the main of which resulting in Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. is due to an infinite loop of component re-rendering, which you force by setting state directly in the function body.
More specifically, this code:
if (
inputCountryCode === responseCountryCodeState &&
inputVatCode === responseVatState
) {
setResult(true);
} else {
setResult(false);
}
force react to re-evaluate the component because you're changing its state by using setResult. When react starts rendering the new body it yet again encounters setResult which results in a new update and re-render which, as you see, leads to a never-ending loop.
Furthermore, you don't need to save the request response to the component state at all, as it is relevant just for the calculation, which is needed only in the form submit handler itself. So, you should ditch the
const [responseVatState, setResponseVatState] = useState("");
const [responseCountryCodeState, setResponseCountryCodeState] = useState("");
state variables altogether. The only state you need except the input value is the validation result.
Also, you have a typo: setResponseVatState(response.data.response.data.VATNumber); should be setResponseVatState(response.data.VATNumber);.
Try this:
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatValue, setVatValue] = useState("");
const [isVatValid, setIsVatValid] = useState(false);
const handelVatState = (event) => {
setVatValue(event.target.value);
};
const closeModalHandler = () => {
setIsVatValid(false);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("[URL]")
.then((response) => {
const inputCountryCode = vatValue.substring(0, 2);
const inputVatCode = vatValue.substring(2);
const { VATNumber, CountryCode } = response.data;
if (inputCountryCode === CountryCode && inputVatCode === VATNumber) {
setIsVatValid(true);
}
else {
setIsVatValid(false);
}
})
.catch((error) => {
console.log(error);
});
};
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
<label className="text-muted">Result : </label>
{isVatValid ? (
<div>{vatValue}</div>
) : (
<div clicked={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
)}
</div>
);
}
export default Form;
Also, I suppose <div clicked={closeModalHandler}> should be <div onClick={closeModalHandler}>?
EDIT:
Here is your solution after comments:
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatValue, setVatValue] = useState("");
const [isVatValid, setIsVatValid] = useState(null);
const handelVatState = (event) => {
setVatValue(event.target.value);
};
const closeModalHandler = () => {
setIsVatValid(null);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("https://vat.erply.com/numbers?vatNumber=BG999999999")
.then((response) => {
const inputCountryCode = vatValue.substring(0, 2);
const inputVatCode = vatValue.substring(2);
const { VATNumber, CountryCode } = response.data;
if (inputCountryCode === CountryCode && inputVatCode === VATNumber) {
setIsVatValid(true);
}
else {
setIsVatValid(false);
}
})
.catch((error) => {
console.log(error);
});
};
const getResultRepresentation = () => {
if (isVatValid === null) {
return null;
}
if (isVatValid) {
return (
<>
<label className="text-muted">Result: </label>
<div>{vatValue}</div>
</>
);
}
else {
return (
<div onClick={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
);
}
}
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
value={vatValue} // <= missing
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
{getResultRepresentation()}
</div>
);
}
export default Form;
And here is a CodeSandbox to test it out.

Dynamically creating and getting inputs

I need to dynamically add new input fields on button click as well as get the user input of those inputs in an array. This is what I have and Im not sure how to do the array. Also on the screen the components only update when I change the state. Not on button click.
This is what I have:
import React, { useState } from 'react'
const CreatePoll = () => {
const [formData, setFormData] = useState({
question: '',
options: ['hi', 'there']
});
const {
question,
options
} = formData;
const addOption = e => {
e.preventDefault();
options.push([''])
console.log(options.length);
}
const handleQuestionChange = (e) => setFormData({
...formData,
[e.target.name]: e.target.value
})
const handleOptionChange = e => setFormData({
...formData
// options: []
})
const handleSubmit = async e => {
e.preventDefault();
console.log(formData)
}
return (
<form onSubmit={handleSubmit}>
<input
placeholder="enter your question"
type="text"
onChange={handleQuestionChange}
name="question" />
{options.map(() => {
return (
<input
placeholder="option"
type="text"
onChange={handleOptionChange}
name="option" />
)
})}
<input type="button" value="Add new option" onClick={addOption} />
<input type="submit" value="Submit" />
</form>
)
}
export default CreatePoll
I tried when addOption button is clicked, I add to the options state an empty string. The length of the array updates but the components on the screen dont until I type in the input box and the state changes. Also I need to map the values of the input boxes to their respective place in the array. They should also be able to edit at any time. How is this done?
Several things are wrong here :
You don't set your state in addOption, don't modify direcly the state object, prefere to destructure array, modify it and set the state.
Your map function don't take any parameter, so it will be the same input names every time, use parameter and index to now which option to change in handleQuestionChange
Your addOption could be improved by using question property directly in you setFormData (it worked like you did it, but it seems to me more clean with this)
import React, { useState } from 'react';
const CreatePoll = () => {
const [formData, setFormData] = useState({
question: '',
options: ['hi', 'there'],
});
const {
question,
options,
} = formData;
const addOption = e => {
e.preventDefault();
const newOptions = [...options];
newOptions.push('');
setFormData({ ...formData, options: newOptions });
console.log(options.length);
};
const handleQuestionChange = e => {
setFormData({
...formData,
question: e.target.value,
});
};
const handleOptionChange = (e, index) => {
const newOptions = [...options];
newOptions[index] = e.target.value;
setFormData({
...formData,
options: newOptions,
});
};
const handleSubmit = async e => {
e.preventDefault();
console.log(formData);
};
return (
<form onSubmit={handleSubmit}>
<input
placeholder="enter your question"
type="text"
onChange={handleQuestionChange}
name="question"
/>
{options.map((opt, index) => (
<input
value={opt}
key={`option_${index}`}
placeholder="option"
type="text"
onChange={e => handleOptionChange(e, index)}
name={opt}
/>
))}
<input type="button" value="Add new option" onClick={addOption} />
<input type="submit" value="Submit" />
</form>
);
};
export default CreatePoll;
to add new options on button click you need to change this function:
const addOption = e => {
e.preventDefault();
options.push([''])
console.log(options.length);
}
to be
const addOption = e => {
e.preventDefault();
const newOptions = {...formData.options}
newOptions.concat([''])
setFormData({...formatData, options: newOptions)}
}

React Axios Input Undefined

I must post {input} data to http://localhost:4000/prediction with Axios. But {input} turns undefined.
I am using const instead of class Main extends component. onChange, it sets form data.
const Main = ({ value, suggestions, auth: { user } }) => {
const [formData, setFormData] = useState("");
const [messages, setMessages] = useState([]);
const { input } = formData;
const onChange = e => setFormData(e.target.value);
const onSubmit = event => {
event.preventDefault();
setMessages(prevMsgs => [...prevMsgs, formData]);
console.log({ input });
Axios post.
axios
.post(
`http://localhost:4000/prediction`,
{ input },
{ crossdomain: true }
)
.then(res => {
console.log(res.data);
//setMessages(prevMsgs => [...prevMsgs, formData]);
})
.catch(error => {
console.log(error.message);
});
};
Return (form) with onSubmit, onChange.
return (
<div className="true">
<br />
<form noValidate onSubmit={e => onSubmit(e)}>
<div className="input-group mb-3">
<input
name="input"
type="text"
className="form-control"
placeholder="Type text"
onChange={e => onChange(e)}
/>
)}
<div className="input-group-append">
<button className="btn btn-outline-secondary">Send</button>
</div>
</div>
</form>
</div>
);
};
As I have mentioned in the comment section formData is a string as I see which does not have a property called input what you try to destructure and that's why it is undefined always.
If you really need that format for axios then you can try change the structure of formData with useState as the following first:
const [formData, setFormData] = useState({input: null});
Then maybe you can try updating as:
const onChange = e => setFormData({input: e.target.value});
I hope that helps!

Categories