I have simple form with dropdown select menu. How do I reset the select field back to show first option after submission ( ---Select category---)? I have tried setCategory("") or setCategory("---Select category---") but it keeps showing category i have picked.
const [category, setCategory] = useState("");
function formSubmit(e) {
e.preventDefault();
firebase
.firestore()
.collection("posts")
.add({
category,
})
.then(() => {
setCategory("");
});
}
<form onSubmit={formSubmit}>
<div>
<label htmlFor="category">Post Category</label>
<select
name="category"
onChange={(e) => setCategory(e.currentTarget.value)}
>
<option value="">--- Select category ---</option>
<option value="react">React</option>
<option value="CSS">CSS</option>
<option value="misc">Misc</option>
</select>
<div>
<button type="submit">Add</button>
</div>
</div>
After doing a little bit of research I found this questions answered here, here, and here. However, I would advice you to use the react-advanced-form library which makes this task a lot easier and will give you more features to implement on your forms.
While using this library you want to use “form.reset()” on your action button. This will let you set initial values for each field and the action will set the values of your fields to this default value. Here is an example:
import React from 'react'
import { Form } from 'react-advanced-form'
import { Input } from 'react-advanced-form-addons'
export default class Example extends React.Component {
handleSubmitted = ({ res, fields, form }) => {
form.reset() // resets "username" field to "admin"
}
render() {
return (
<Form onSubmitted={this.handleSubmitted}>
<Input
name="username"
initialValue="admin" />
</Form>
)
}
}
Related
I am attempting to create a dynamic form in which there are 2 text fields and one dropdown select. These fields can be added by clicking the "Add More.." button. The remove button removes a particular field set. After an npm start the code shows all elements normally, add, remove and input fields work as intended. However, the problem starts when the select is used. On selecting something, the app crashes and gives a white screen with the errors [tag:"formFields.map is not a function"] and [tag:"Consider adding an error boundary to your tree to customize error handling behavior."] I would appreciate any help that can resolve this. :)
P.S. I am learning react through building projects rather than the conventional method of sitting through hours of tutorials and figuring things out. I am grateful to any help that is offered to me.
import { useState } from "react";
function FoodPreferences(){
const [formFields, setFormFields] = useState([
{ name: '', age: '', food: '' }
])
const [foodState, setFoodState] = useState("dumpling");
const handleFormChange = (event, index) => {
let data = [...formFields];
data[index][event.target.name] = event.target.value;
setFormFields(data);
}
const handleSelectChange = (event, index) => {
const selectedFood = event.target.value
setFormFields(selectedFood)
}
const submit = (e) => {
e.preventDefault();
console.log(formFields, foodState)
}
const addFields = () => {
let object = {
name: '',
age: '',
food: ''
}
setFormFields([...formFields, object])
}
const removeFields = (index) => {
let data = [...formFields];
data.splice(index, 1)
setFormFields(data)
}
return (
<div className="App">
<form onSubmit={submit}>
{formFields.map((form, index) => {
return (
<div key={index}>
<input
name='name'
placeholder='Name'
onChange={event => handleFormChange(event, index)}
value={form.name}
/>
<input
name='age'
placeholder='Age'
onChange={event => handleFormChange(event, index)}
value={form.age}
/>
<select
className="custom-select"
value={form.food}
onChange={event => handleSelectChange(event,index)}
>
<option value="steak">Steak</option>
<option value="sandwich">Sandwich</option>
<option value="dumpling">Dumpling</option>
</select>
<button onClick={() => removeFields(index)}>Remove</button>
</div>
)
})}
</form>
<button onClick={addFields}>Add More..</button>
<br />
<button onClick={submit}>Submit</button>
</div>
);
}
export default FoodPreferences;
I have tried using the select component alone without looping it and it worked fine. The errors pop up when select component is placed under a map() for dynamic inputs (Adding or Removing Fields). I know that the error is either in the onChange part of my code for the select component or the handleSelectChange
import React, {useState} from 'react';
function FoodChoice() {
const \[foodState, setFoodState\] = useState("dumpling");
return (
<div className="container p-5">
<select
className="custom-select"
value={foodState}
onChange={(e) => {
const selectedFood = e.target.value;
setFoodState(selectedFood);
}}
>
<option value="steak">Steak</option>
<option value="sandwich">Sandwich</option>
<option value="dumpling">Dumpling</option>
</select>
{foodState}
</div>
);
}
export default FoodChoice;
I'm using the below Contact component to handle a simple form in react to send an email. I want the sendEmail function to also clear the form fields but I've tried referencing them through form.current and that doesnt seem to be working. Is there another way I need to reference them to set the values? I also tried e.target.reset() and it didn't seem to do anything.
import React, { useRef } from 'react';
import emailjs from 'emailjs-com';
const Contact = () => {
const form = useRef();
const sendEmail = (e) => {
e.preventDefault();
const serviceId='...';
const templateId='...';
const userId='...';
emailjs.sendForm(serviceId, templateId, form.current, userId)
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
};
return (
<form onSubmit={sendEmail} ref={form}>
<div className="field half first">
<label htmlFor="name">Name</label>
<input type="text" name="fromName" id="name"/>
</div>
<div className="field half">
<label htmlFor="email">Email</label>
<input type="text" name="fromEmail" id="email"/>
</div>
<div className="field">
<label htmlFor="message">Message</label>
<textarea name="message" id="message" rows="4"
placeholder = "..."></textarea>
</div>
<ul className="actions">
<li>
<input type="submit" value="Send Message" className="special"/>
</li>
</ul>
</form>
);
};
export default Contact
There are so many ways to doing this, basically on how the component has been structured to collect the data. However, following your pattern of arrangement, why don't you set a boolean variable or something coercible to a boolean value (value initially set to false) that is made aware (i.e value changes to true or 'sent') when the email has been successfully sent.
import {useState} from "react";
const [emailStatus, setEmailStatus] = useState("Not sent");
Then use the useEffect-hook to re-render the component, whenever the emailStatus variable changes to true or 'sent' and thereby clear-out the form values.
Hence, in your function:
emailjs.sendForm(serviceId, templateId, form.current, userId)
.then((result) => {
.... any other logic
console.log(result.text);
setEmailStatus('sent');
................
useEffect(() => {
//clear form fields here
}, [emailStatus]);
return(
.....
.....
);
I would like to auto-fill a text field based on the selection made in a dropdown, I thought that the state change would cause the form to re-render and thus create the desired effect, however this is not the case.
Here is the minimum working example that demonstrates my problem.
import React from 'react';
import { useForm } from 'react-hook-form';
function FormTest (){
const [dropdownValue, setDropdownValue] = React.useState('Option 1');
const { register, handleSubmit } = useForm({
defaultValues: {
textfield: dropdownValue,
},
mode: 'onChange'
},);
const onSubmit = (form) => {
alert(JSON.stringify(form))
}
return(
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<select name='dropdown'
ref={register}
value={dropdownValue}
onChange={(e) => setDropdownValue(e.currentTarget.value)}>
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
</select>
<input type='text'
name="textfield"
ref={register}
/>
<input type='submit'/>
</form>
</div>
);
}
export default FormTest;
When I change the dropdown from Option 1 to Option 2, dropdownValue is changed to Option 2 however, the text in the text field remains as Option 1. Is there a way to get this updating? Perhaps a forced re-render of the text field? Or is this not possible?
Thanks
You can use setValue from "react-hook-form":
const { register, handleSubmit, setValue } = useForm({ // setValue
// ...
})
setValue will accept the name and the new value:
onChange={(e) => {
setDropdownValue(e.currentTarget.value)
setValue('textfield', e.currentTarget.value)
}}
onSubmit(values) {
console.log("i m clicked", values); /// i didn't get form values
here.
}
renderMacros() {
const { handleSubmit } = this.props;
const macrosData = this.props.macros.macros;
const categoryMacrosData = this.props.categoryMacros.category;
console.log("categoryMacrosData", categoryMacrosData);
const { open } = this.state;
if (macrosData) {
return (
<div>
<div className="form-block-5 w-form">
<form
id="macros-form"
name="macros-form"
onSubmit={handleSubmit(this.onSubmit)}
>
<div className="row">
<div className="col-sm-12">
<label>Type</label>
<Field // this works fine
name="category"
options={MACRO_TYPE_CATEGORIES}
placeholder="Type"
component={SelectInput}
set_default="true"
/>
</div>
<div className="col-sm-12">
<Field // this works fine
name="name"
placeholder="Name Ex. Follow-up template"
component={renderField}
type="text"
className="text-fields w-input"
id="macros_name"
/>
</div>
<div className="col-sm-12">
<Field // here is the problem
type="text"
name="categoryId"
options={categoryMacrosData}
placeholder="Search or add category "
component={AsyncMulti}
handleSelect={this.handleSelectChange}
/>
</div>
</div>
<button>Create Macro</button>
</form>
</div>
</div>
);
}
}
Bottom line is if i use Creatable component of react-select library, i
couldn't get selected values.
My component file: components/Multi.js
import React from "react";
import CreatableSelect from "react-select/lib/Creatable";
const MultiSelect = props => {
const { options, handleSelect } = props;
return <CreatableSelect isMulti onChange={handleSelect} options=
{options} />;
};
export default MultiSelect;
I am using react-select for select options in redux form. After
submitting form, I am unable to get form submitted values.
I am using react-select library https://react-select.com/creatable with redux form.
Given a props name in <Select> like
<Select
name = {"inputName"} // <- if you submit the form you will get vale like {"inputName":test111}
options = {[{ value: 'test111', label: 'Chocolate' }]}
/>
You are not binding handleSubmit properly as well not using refs since you are not getting the values.
I suggest you to try with the binding code in your <form> tag:
<form
id="macros-form"
name="macros-form"
onSubmit={this.handleSubmit.bind(this)}
>
Also pass refs in your field tag to get the value:
<Field
name="categoryId"
options={categoryMacrosData}
placeholder="Search or add category "
component={Multi}
handleSelect={this.handleSelectChange}
ref="categoryId"
/>
Instead of writing onSubmit function:
onSubmit(values) {
console.log("i m clicked", values); /// i didn't get form values
here.
}
Replace it with this function code:
handleSubmit(event) {
if (this.refs.categoryId !== '') {
event.preventDefault();
console.log('categoryId: ', this.refs.categoryId.value)
}
}
Hope it helps you!
I am new to react and redux-form. I have a form that rendered select field options with data I get from an API. It query new API with key value from the select field whenever I choose an option. Then I want the other two fields to display and set their value base on the new API query which happen every time I choose new option. Placing the value on the field's placeholder only display the value but it will not capture the value when submit. I test this by using values from redux-form-website-template. It only show the key and value from the select field but not other fields. What should I do in order to capture the value every time I change the select field option? Will formalize or format do the job? I tried value={this.value} and not working.
//All relevant imports
class MyFormClass extends Components {
componentDidMount() {
//first query
this.props.dispatch(getFoodAction())
}
onChange = (event) => {
//second API query with the key value from select
this.props.dispatch(getFoodByIDAction(event.target.value))
}
render() {
const { handleSubmit, fruit } = this.props
let food_list = this.props.food.map((food, index) => {
return (
<option value={ food.id } >
{ food.name }
</option>
)
})
return(
<form onSubmit={ handleSubmit(this.submit) } >
<div>
<Field
value={this.value}
name="food"
component="select"
onChange={this.onChange.bind(this)} >
{food_list}
</Field>
<div>
<label><b>Food Category</b> : </label>
<Field
name="food_category"
component="input"
type="text"
placeholder={ food.category}
/>
</div>
<div>
<label><b>Food Detail</b> : </label>
<Field
name="food_detail"
component="textarea"
type="text"
placeholder={ food.detail}
/>
</div>
</div>
</form>
)
}
}
const reduxFormFood = reduxForm({
form: 'foodForm'
})(MyFormClass)
function mapStateToProps(state) {
return {
food: state.foodreducer.food,
foodbyid: state.foodbyidreducer.food
}
}
export default connect(
mapStateToProps,
{ getFoodAction, getFoodByIDAction }
)(reduxFormFood );
Eventually I rewrite the whole component, new reducer and new action by referencing the redux-form initializefromstate example