I have created a user registration form which contains of firstname,lastname,email etc.
Here a user can add n number of emails.For this,I have created a button and onClick it should open the input field.
<--Here is the code -->
const [formData, setFormData] = useState({
firstname: "",
lastname: "",
email: "",
})
const handleChange = (e) => {
const { name, value } = e.target;
setFormData({ ...formData, [name]: value });
};
const handleSubmit = async (e) => {
e.preventDefault();
const newStudent = {
firstname,
lastname,
email,
}
try {
const config = {
headers: {
"Content-Type": "application/json",
},
};
const body = JSON.stringify(newStudent);
await axios.post(`http://localhost:5000/student`, body, config);
}
const handleClick = () => {
return <Input type="email" name="email" value={email} onChange={handleChange} />
};
return (
<Form className={classes.root} onSubmit={handleSubmit}>
<div>
<Input
id="standard-multiline-flexible"
label="First Name"
multiline
name="firstname"
value={firstname}
onChange={handleChange}
/>
</div>
<div>
<Input
id="standard-multiline-flexible"
label="Last Name"
name="lastname"
value={lastname}
onChange={handleChange}
multiline
/>
</div>
<div>
<Input
id="standard-multiline-static"
type="email"
label="Email"
name="email"
onChange={handleChange}
value={email}
multiline
/>
<button className="btn btn-primary" onClick={handleClick}>
Add
</button>
<PrimaryButton>Submit</PrimaryButton>
</Form>
)
Can anyone tell me how should I define the handleClick() so that whenever I click the add button,it renders a new Input field?
Another way you could achieve this if you want the user to see their input emails remove them etc is to do the following:
Create an emails state array.
Add an email text field with an add button next to it.
When the user enters an email and presses add, add that email to the array.
You can then map the array to show the added emails as a list with the option to delete the emails if the user decides to.
At the end of handle click
Instead of doing this
return <Input type="email" name="email" value={email} onChange={handleChange} />
Do this ->
setFormData({firstname: "",lastname: "",email: ""});
Edits
You can display the emails via a list after making the API call
You can have a delete button to delete that email from the list.
"There are n ways to implement. Please be more specific"
Related
I am messing around with Riot's API that allows getting information of a player by the player's name. I am trying to get an API key (I only got a 24 hour key) and the target player's name from users' input.
export function PlayerSearch() {
function handlesubmit(e) {
console.log(e.target);
e.preventDefault();
}
return (
<div className='player'>
<div className='inputfield'>
<form onSubmit={handlesubmit} method='GET' autoComplete="off">
<div>
<label htmlFor="key">Your API key:</label>
<input
placeholder='Your API key'
onFocus={(e)=>{e.target.placeholder=''}}
type="text"
id="key"
name="key" />
</div>
<div>
<label htmlFor="name">Player name:</label>
<input
placeholder='Player name'
onFocus={(e)=>{e.target.placeholder=''}}
type="text"
id="name"
name="name" />
</div>
<div>
<input type='submit' />
</div>
</form>
</div>
</div>
);
}
And I got this in the console:
So how exactly do I extract the two inputs from the form?
In addition, is it possible that I can call another component and pass data as props to handle the submitted data so that the code is cleaner?
You should have a state to store your inputs:
const [formData, setFormData] = useState({ key: "", name: "" });
Then you need a function that gets called onChange of your input fields to update your state:
const onChange = (event) => {
setFormData({ ...formData, [event.target.name]: event.target.value });
};
And you need to pass that function to your input onChange property:
<input
placeholder="Your API key"
onFocus={(e) => {
e.target.placeholder = "";
}}
type="text"
name="key"
value={formData.key}
onChange={onChange}
/>
Then you can access the state in your handleSubmit:
function handlesubmit(e) {
console.log(formData);
e.preventDefault();
}
In the tutorials I've found, the best way to capture forms inputs, is to use a "onchange" handler.
However, how should we deal with fields that are left to the default value ?
For example in something like the example below, if "country" is left to the default value, the "formData" will never get it.
const [formData, setFormData] = useReducer(formReducer, {});
const handleChange = event => {
setFormData({
name: event.target.name,
value: event.target.value,
});
}
const handleSubmit = event => {
event.preventDefault();
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
};
fetch('http://0.0.0.0:8000/add_user/', requestOptions)
}
<form onSubmit={handleSubmit}>
<fieldset>
<input type="text" name="name" placeholder="Name" onChange={handleChange} />
<input type="text" name="country" value="" onChange={handleChange} required />
</fieldset>
<Button type="submit">Submit</Button>
</form>
I've thought about some solutions but I don't think they are the best practices. For example, adding a snippet of code that manually assigns all default values to the form in the construction, so the formData is pre-filled.
Is there a clean & nice way to do it ?
In your useReducer hook you should store initial country value and then assign it to the value in country input, like below:
const [formData, setFormData] = useReducer(formReducer, { country: "" });
<form onSubmit={handleSubmit}>
<fieldset>
<input type="text" name="name" placeholder="Name" onChange={handleChange} />
<input type="text" name="country" value={formData.country} onChange={handleChange} required />
</fieldset>
<Button type="submit">Submit</Button>
</form>
Hi everybody Tring to make a form with Form provided by bootstap but it doesn't work.
If I insert value it doesn't let me type, without value I digit but I can't get the value.
(I have also a Gatsby theme activated)
const StandAdd = () => {
const [item, setItem] = useState({
title: "",
kindof: "",
website: "",
image01: "",
image02: "",
image03: "",
})
const { title, kindof, website, image01, image02, image03 } = item
const handleInputChange = event => {
event.preventDefault()
setItem({ ...item, [event.target.name]: event.target.value })
}
const handleSubmit = event => {
event.preventDefault()
alert(`${title} ${item} ${website}`) // always empty I gat get anything
}
return (
<Layout>
<form onSubmit={handleSubmit}>
<Form>
<Form.Group controlId="title">
{/* <Form.Label>Email address</Form.Label> */}
<Form.Control
value={titlet} // <-- this blocks the typing
type="text"
placeholder="Enter Stand's Name"
onChange={handleInputChange}
/>
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</form>
</Layout>
)
}
export default StandAdd
Any idea?
The issue is here:
<Form.Control
value="title" // <-- this blocks the typing
type="text"
placeholder="Enter Stand's Name"
onChange={handleInputChange}
/>
here you have to provide the name attribute so that your code:
setItem({ ...item, [event.target.name]: event.target.value })
will get some value in event.target.name.
So after adding name the code will be like:
<Form.Control
type="text"
name="title" <---- name added here
placeholder="Enter Stand's Name"
onChange={handleInputChange}
/>
And don't provide a hard-coded value to input like this:
value="title"
instead use defaultValue for providing an initial value.
I think you need to provide name attribute to <Form.Control> component.
I want to make good pop up to my project with sweetalert when the passwords don't match:
const SignUp = ({ signUpStart, userError, resetError }) => {
const [userCredentials, setUserCredentials] = useState({
displayName: "",
email: "",
password: "",
confirmPassword: "",
});
const { displayName, email, password, confirmPassword } = userCredentials;
const handleSubmit = async (event) => {
event.preventDefault();
if (password !== confirmPassword) {
alert(`password don't match`);
return;
}
signUpStart({ displayName, email, password });
};
const handleChange = (event) => {
const { name, value } = event.target;
setUserCredentials({ ...userCredentials, [name]: value });
};
return (
<div className="signup">
<h2 className="title">I do not have a account</h2>
<span>Sign up with your email </span>
<form className="sign-up-form" onSubmit={handleSubmit}>
<Form
type="text"
name="displayName"
value={displayName}
onChange={handleChange}
label="Display Name"
required
></Form>
<Form
type="email"
name="email"
value={email}
onChange={handleChange}
label="Email"
required
></Form>
<Form
type="password"
name="password"
value={password}
onChange={handleChange}
label="Password"
required
></Form>
<Form
type="password"
name="confirmPassword"
value={confirmPassword}
onChange={handleChange}
label="Confirm Password"
required
></Form>
<CustomButton type="submit">SIGN UP</CustomButton>
</form>
{userError && userError.message ? (
<SweetAlert
show={!!userError.message}
type="warning"
title="Something went wrong"
text={userError.message}
onConfirm={() => resetError()}
/>
) : null}
</div>
);
};
EDIT: i add my whole component to the question. i deleted my mapstatetoprops and dispatch.
So i basically want to run once when i hit my submit button.
I want to make the alert in the if statement. But I think I need to refactor little. Can anyone help with this?
I have a form which has 5 input text type fields and a input file type field. I used onChange function.
this is the form
<form onSubmit ={this.onSubmit.bind(this)} >
<FormGroup bssize="sm">
<input onChange={this.handleChange} className="form-control" type="text" placeholder="Company Name" name="companyName" ref="companyName"/>
</FormGroup>
<FormGroup bssize="sm">
<input onChange={this.handleChange} className="form-control" type="text" placeholder="Account Name" name="AccountName" ref="AccountName" />
</FormGroup>
<FormGroup bssize="sm">
<input onChange={this.handleChange} className="form-control" type="text" placeholder="Bank Name" name="bankName" ref="bankName"/>
</FormGroup>
<FormGroup bssize="sm">
<input onChange={this.handleChange} className="form-control" type="text" placeholder="Branch" name="branch" ref="branch"/>
</FormGroup>
<FormGroup bssize="sm">
<input onChange={this.handleChange} className="form-control" type="text" placeholder="Account Number" name="accountNo" ref="accountNo"/>
</FormGroup>
<FormGroup>
<span>Bank Book Copy</span>
<input style={{display :'none'}} type="file" onChange={this.fileSelectedHandler} ref={fileInput => this.fileInput = fileInput } />
<Button onClick={()=>this.fileInput.click()} >
<Icon type="upload" /> Click to upload
</Button>
</FormGroup>
<input onClick={this.fileUploadHandler} className="btn btn-primary" bsstyle="success" name="submit" type="submit" value="Submit" />
</form>
now my problem is which filed filled at last only post into my API.I used AXIOS for HTTP request.
I used storage-connector for upload images
below I mentioned my onChange function
constructor(props){
super(props);
this.state = {
companyName : '',
AccountName : '',
bankName : '' ,
bankBookCpy : '' ,
accountNo : '' ,
branch : '' ,
BankList : '',
selectedFile : null,
}
}
fileSelectedHandler = event =>{
this.setState({
selectedFile: event.target.files[0]
})
}
handleChange = event => {
this.setState({
companyName: event.target.value,
AccountName: event.target.value,
bankName: event.target.value,
accountNo: event.target.value,
branch: event.target.value
});
}
fileUploadHandler = () => {
const fd = new FormData();
fd.append('image',this.state.selectedFile, this.state.selectedFile.name )
axios.post('http://localhost:3000/api/attachmentBanks/bankBookCpy/upload',fd , {
onUploadProgress : ProgressEvent => {
console.log('Upload Progress: ' + Math.round(ProgressEvent.loaded / ProgressEvent.total *100) + '%')
}
})
.then(res => {
this.setState({
BankList: res.data.result.files.image[0].name,
});
});
}
AddMeetup(newMeetup){
axios.request({
method:'post',
url:'http://localhost:3000/api/companyBankDetails',
data : newMeetup
}).then(response => {
this.props.history.push('/');
}).catch(err => console.log(err));
onSubmit(e){
const newMeetup = {
companyName: this.state.companyName,
AccountName : this.state.AccountName,
bankName : this.state.bankName,
branch : this.state.branch,
accountNo : this.state.accountNo,
bankBookCpy : this.state.BankList
}
this.AddMeetup(newMeetup);
e.preventDefault();
}
Above functions are only stored last onChange value
You can handle it like this:
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
};
First change you handleChange function to the following :
handleChange = name => event => {
this.setState({ [name]: event.target.value} );
}
Then send your name argument to the onChange function :
<form onSubmit ={this.onSubmit.bind(this)} >
{
Object.entries({
"Company Name": "companyName",
"Account Name": "AccountName",
"Bank Name": "bankName",
"Branch": "branch",
"Account Number": "accountNo"
}).map(([field, name]) =>
<FormGroup bssize="sm" key={name}>
<input onChange={this.handleChange(name)} className="form-control" type="text" placeholder={field} name={name} ref={name} />
</FormGroup>)
}
<FormGroup>
You can avoid repetitions in your code by also mapping an array to create your form
Here your issue is you call same handleChange() Function on each onChange event. let's assume you change "company name" input field. When you change it you will call the handleChange() function. Then inside that function, you assign event.target.value to all of the fields(companyName, AccountName, etc). But event.target.value only give you the data from the field that you are changing to call the handleChange() method, In this case, it is "company Name" input. So this will replace all of your form data states with the text you entered in "Company Name".
So, the hard way is you can create separate functions to handle each input fields. But it is not good practice. Instead, you can do as answered by SakoBu.
that method will take state name from event.target.name and state data from event.target.value. So if you change the value of "Company Name" your state update code in the handleChange() will be the same as companyName: event.target.value, but only change CompanyName state, not other form states.
You don't need to worry about image uploading system. Because you can use your existing fileUploadHandler() method to handle the changes of the file uploading.
As answered by SakoBu, the approach would solve your problem.
One thing I noticed is you are assigning ref to each input field, you don't need to do so.
Please do remember that if input type is checkbox,radiobutton you will get corresponding value by event.taget.checked.
It's always a good practise to check event type, by event.target.type.
For more details visit :-
https://reactjs.org/docs/forms.html
Hope this Helps,
Cheers !!