I follow to this code:
import React from 'react';
import { Formik, Form, Field, FieldArray } from 'formik';
// Here is an example of a form with an editable list.
// Next to each input are buttons for insert and remove.
// If the list is empty, there is a button to add an item.
export const FriendList = () => (
<div>
<h1>Friend List</h1>
<Formik
initialValues={{ friends: ['jared', 'ian', 'brent'] }}
onSubmit={values =>
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
}, 500)
}
render={({ values }) => (
<Form>
<FieldArray
name="friends"
render={arrayHelpers => (
<div>
{values.friends && values.friends.length > 0 ? (
values.friends.map((friend, index) => (
<div key={index}>
<Field name={`friends.${index}`} />
<button
type="button"
onClick={() => arrayHelpers.remove(index)} // remove a friend from the list
>
-
</button>
<button
type="button"
onClick={() => arrayHelpers.insert(index, '')} // insert an empty string at a position
>
+
</button>
</div>
))
) : (
<button type="button" onClick={() => arrayHelpers.push('')}>
{/* show this when user has removed all friends from the list */}
Add a friend
</button>
)}
<div>
<button type="submit">Submit</button>
</div>
</div>
)}
/>
</Form>
)}
/>
</div>
);
But that for text input Field.
I want to replace to select and I do something like that.
Replace:
<Field name={`issues.${index}`} />
To:
<Field component="select" name="color">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</Field>
I add 3 component when I choose the value in one component, It's effect to all of the component.
What did I wrong here?
The name property for each select input needs to be unique. Try the following
<Field component="select" name={`friends.${index}`}>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</Field>
Related
Proper way to do bulk update of documents in react.
I want to bulk update all posts status and type fields in one single query how to achieve it.
Status and Type are dropdown select inputs.
All Posts Component:-
const AllPosts = () => {
const [updateObj ,setUpdateObj] = useState({})
handleUpdate(){
}
return (
<>
<div>
{AllPosts.map((post, index) => (
<Post
key={post._id}
postId={post._id}
postStatus={post.status}
postType={post.type}
postSubject={post.subject}
checked={post?.isChecked || false}
onChange={handleAllChecked}
checkBoxName={post._id}
/>
))}
</div>
</>
);
};
export default AllPosts;
I think I would need an update object which would have post id as key and status and type as its value.
Post component
const Post = ({
postId,
postStatus,
postType,
postSubject,
checked,
onChange,
checkBoxName,
}) => {
return (
<div className="post">
<div className="post-checkbox">
<input
type="checkbox"
id="post-checkbox"
name={checkBoxName}
checked={checked}
onChange={onChange}
/>
</div>
<div>
<div>{postSubject}</div>
<div className="options">
<select onChange={onChange}>
<option>Status A</option>
<option>Status B</option>
<option>Status C</option>
</select>
<select onChange={onChange}>
<option>Type A</option>
<option>Type B</option>
<option>Type C</option>
</select>
</div>
</div>
</div>
);
};
export default Post;
I'm trying to get all selected values from a react-bootstrap Form. On the latest version of bootstrap e.target.value only seems to contain a single value instead of a list when multiple values are selected by shift clicking multiple lines. How can I get all selected values? Preferably by key or id.
const Form = ReactBootstrap.Form;
const Button = ReactBootstrap.Button;
const ExampleForm = () => {
const [output, setOutput] = React.useState("");
function changeSelection(e) {
setOutput(e.target.value);
}
function handleSubmit(e) {
e.preventDefault();
}
return(
<Form onSubmit={handleSubmit}>
<Form.Group controlId="dimension">
<Form.Control
as="select"
multiple
onChange={changeSelection}>
<option key="1" id="1" >1</option>
<option key="2" id="2" >2</option>
<option key="3" id="3" >3</option>
<option key="4" id="4" >4</option>
</Form.Control>
<Button type="submit" variant="primary">
select
</Button>
</Form.Group>
Output: {output}
</Form>
);
}
ReactDOM.render(
<ExampleForm />,
document.getElementById('app')
);
Codepen example can be found here
Turns out you can use Array.from
Array.from(e.target.selectedOptions, option => option.value)
Found here
I have a select component that needs to reset to the "Neutral" state after user clicks the next button. However it just continuing to show which ever the user previously selected. I have them split over the components as outlined below. You can see when the next button is pressed, the defaultValue is reset to '3', however this only seems to work for when the component first renders and never again on subsequent presses.
const QuestionLikert = ({ nextQuestion, prevQuestion, setLikertResponse, likertResponse }) => {
return (
<div className='section'>
<div className='container'>
<div>
<div>
<select
id='response'
name='response'
onChange={setLikertResponse}
defaultValue={likertResponse}
>
<option value="1">Strongly Disagree</option>
<option value="2">Disagree</option>
<option value="3">Neutral</option>
<option value="4">Agree</option>
<option value="5">Strongly Agree</option>
</select>
</div>
<button onClick={nextQuestion}>
Next
</button>
<div>
<span onClick={prevQuestion}>Back </span>
</div>
</div>
</div>
</div>
)}
const ParentComponent = () => {
const [currentQuestion, setCurrentQuestion] = useState(0)
const [likertResponse, setLikertReponse] = useState('3')
const handleLikertInput = (e) => {
setLikertReponse(e.target.value)
}
const toggleNextQuestion = () => {
setLikertReponse('3')
setCurrentQuestion(currentQuestion + 1)
}
const togglePrevQuestion = () => {
setCurrentQuestion(currentQuestion - 1)
}
return (
<Layout>
<div className='section'>
<div className='container'>
<div>
<QuestionLikert
nextQuestion={toggleNextQuestion}
prevQuestion={togglePrevQuestion}
setLikertResponse={handleLikertInput}
likertResponse={likertResponse}
/>
</div>
</div>
</div>
</Layout>
)
}
The <select>'s value param in QuestionLikert should be controlled by the likertResponse prop, as its state comes from ParentComponent
<select
id='response'
name='response'
onChange={setLikertResponse}
value={likertResponse}
>
<option value="1">Strongly Disagree</option>
<option value="2">Disagree</option>
<option value="3">Neutral</option>
<option value="4">Agree</option>
<option value="5">Strongly Agree</option>
</select>
I am using AntD select.
When I put select into a separate component, the form does not see the value
Tell me why the form does not receive data on submit ?
Example
const SelectCust = () => {
return (
<Select
mode="multiple"
placeholder="Please select favourite colors"
style={{ width: 500 }}
name="select-multiple"
>
<Option value="red">Red</Option>
<Option value="green">Green</Option>
<Option value="blue">Blue</Option>
</Select>
)};
const Demo = () => {
const onFinish = values => {
console.log("Received values of form: ", values); // {custom:undefined}
};
return (
<Form name="validate_other" onFinish={onFinish}>
<Form.Item name="custom" label="Select custom">
<SelectCust />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
)};
If you wrap <Select> with <Form.Item> it works correctly:
const SelectCust = () => {
return (
<Form.Item name="custom" label="Select custom">
<Select
mode="multiple"
placeholder="Please select favourite colors"
style={{ width: 500 }}
name="select-multiple"
>
<Option value="red">Red</Option>
<Option value="green">Green</Option>
<Option value="blue">Blue</Option>
</Select>
</Form.Item>
);
};
Here is updated Demo component:
const Demo = () => {
const onFinish = values => {
console.log("Received values of form: ", values);
};
return (
<Form name="validate_other" onFinish={onFinish}>
<SelectCust />
<Form.Item
wrapperCol={{
span: 12,
offset: 6
}}
>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
EDIT 1
It seemed wrong to me that wrapping <Select> with <Form.Item> solved the problem, so I looked up <Form> documentation.
Here is updated code:
const SelectCust = props => {
return (
<Select
mode="multiple"
placeholder="Please select favourite colors"
onChange={props.onColorChange}
>
<Option value="red">Red</Option>
<Option value="green">Green</Option>
<Option value="blue">Blue</Option>
</Select>
);
};
const Demo = () => {
const [form] = Form.useForm();
const onFinish = values => console.log(values);
const handleColorChanged = value => {
form.setFieldsValue({ custom: value });
};
return (
<Form name="validate_other" form={form} onFinish={onFinish}>
<Form.Item name="custom" label="Select custom">
<SelectCust onColorChange={handleColorChanged} />
</Form.Item>
<Form.Item
wrapperCol={{
span: 12,
offset: 6
}}
>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
Update has 3 important steps:
Add const [form] = Form.useForm() in the beginning of Demo component
Implement handleColorChanged function and pass it as props to SelectCust. Handler sets form value by calling form.setFieldsValue().
Pass from as props to <Form> component
I want to retrieve the value from my selection so I can make post requests. I have no problem getting from text input, but for some reason I can't get it from the drop down menu select. I end up getting a
"TypeError: Cannot read property 'value' of undefined"
Here is the code I am using.
import React from "react";
import { Form, Input, Button, Select } from "antd";
const { Option } = Select;
class ItemForm extends React.Component {
handleFormSubmit = event => {
event.preventDefault();
const name = event.target.elements.name.value;
const description = event.target.elements.description.value;
const category = event.target.elements.category.value;
console.log(name, description, this.refs.category.value);
};
render() {
return (
<div>
<Form onSubmit={this.handleFormSubmit}>
<Form.Item label="Form Layout" />
<Form.Item label="Product Name">
<Input name="name" placeholder="Ex: Organic Apple..." />
</Form.Item>
<Form.Item label="Description">
<Input name="description" placeholder="Ex: Juicy organic apples!" />
</Form.Item>
<Form.Item label="Category">
<Select name="category" placeholder="Please select a category">
<Option value="Fruit">Fruit</Option>
<Option value="Vegetable">Vegetable</Option>
<Option value="Poultry">Poultry</Option>
</Select>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
</div>
);
}
}
export default ItemForm;
Use onChange which is fired when the value of the select changes. antd select documentation
<Form.Item label="Category">
<Select
onChange={(value) => {
alert(value)
}}
name="category"
placeholder="Please select a category">
<Option value="Fruit">Fruit</Option>
<Option value="Vegetable">Vegetable</Option>
<Option value="Poultry">Poultry</Option>
</Select>
</Form.Item>
working example
Something similar to the classic javascript approach, you intended to use, could be use getFieldValue.
But coupling to coherent createRef , Form and Form.Item as below.
When getting values, remember to reference the Form.Item name and not the Input one ;-)
I have created a sandbox demo hoping other people will enjoy or contribute.
import React from "react";
import { Form, Input, Button, Select } from "antd";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css"; //export default ItemForm;
const { Option } = Select;
class ItemForm extends React.Component {
formRef = React.createRef();
handleFormSubmit = event => {
event.preventDefault();
console.log("All field values", this.formRef.current.getFieldsValue());
const name = this.formRef.current.getFieldValue("productName"); //OLD event.target.elements.name.value;
const description = this.formRef.current.getFieldValue("description"); //OLD event.target.elements.description.value;
const category = this.formRef.current.getFieldValue("category"); //OLD event.target.elements.category.value;
console.log(name, description, category);
alert(`${name}, ${description}, ${category}`);
};
render() {
return (
<div>
<Form ref={this.formRef} onSubmit={this.handleFormSubmit}>
<Form.Item label="Form Layout (Form.Item-createRef-getFieldValue Example)" />
<Form.Item label="Product Name" name="productName">
<Input name="name" placeholder="Ex: Organic Apple..." />
</Form.Item>
<Form.Item label="Description" name="description">
<Input name="description" placeholder="Ex: Juicy organic apples!" />
</Form.Item>
<Form.Item label="Category" name="category">
<Select name="category" placeholder="Please select a category">
<Option value="Fruit">Fruit</Option>
<Option value="Vegetable">Vegetable</Option>
<Option value="Poultry">Poultry</Option>
</Select>
</Form.Item>
<Form.Item>
<Button
type="primary"
htmlType="submit"
onClick={this.handleFormSubmit}
>
Submit
</Button>
</Form.Item>
</Form>
</div>
);
}
}
ReactDOM.render(<ItemForm />, document.getElementById("container"));
Managed it by using onChange as shown below this.
state = {
status: ""
};
<Form.Item label="Status">
<Select
name="status"
onChange={value => {
this.setState({ status: value });
}}
placeholder="Please choose the status"
>
<Option value="new">New</Option>
<Option value="open">Open</Option>
<Option value="rejected">Rejected</Option>
<Option value="deferred">Deferred</Option>
<Option value="reopened">Reopened</Option>
</Select>
</Form.Item>
unlike what you would expect, in Ant Design Select you can't get the value by calling:
onChange={(e)=>console.log(e.target.value)}
no. instead you get the value directly by just accessing the event itself, like this:
onChange={(e)=>console.log(e)}
You can fix this as follows. (Works fine for Antd)
<Select
onChange={(text, index) => {
console.log(index.children);
}}
>
A better and cleaner way to avoid this issue is to define all the form values and labels in an array and pass it into the . Declare or use an onChange event and store the value of the event in your state.