How to dynamically build a redux form? - reactjs

I'm looking to learn how to dynamically build a redux-form. Idea being, the component called, componentDidMount goes at fetches a list of items from the server and inserts them in the store, store.my_items:
{'item1', 'itemB', 'itemZZZ', etc...}
Now that these items are in the store, I want to build the redux-form with a Field for each item in store.my_items.
Example, several of these dynamically created:
<div>
<label>ItemXXX</label>
<div>
<label>
<Field name="ItemXXX" component="input" type="radio" value="1" />
{' '}
1
</label>
<label>
<Field name="ItemXXX" component="input" type="radio" value="2" />
{' '}
2
</label>
</div>
</div>
With react, redux-form, what would be the right way to approach building this type of dynamic redux form?
Thank you

I am following this approach for building a form dynamically. I am just declaring metadata of form fields (type, placeholder, the unique name of each field, etc.) like this:
const fields = [
{ name: 'name', type: 'text', placeholder: 'Enter Name' },
{ name: 'age', type: 'number', placeholder: 'Enter age' },
{ name: 'email', type: 'email', placeholder: 'Enter Email' },
{ name: 'employed', type: 'checkbox' },
{
name: 'favouriteColors',
type: 'select',
options: [
{ label: 'Red', value: 'red' },
{ label: 'Yellow', value: 'yellow' },
{ label: 'Green', value: 'green' },
],
},
]
Now, I am just iterating over these fields and rendering input for each field like the way I have done in renderField component given below. My general form component looks like this:
import React from 'react'
import { Field, reduxForm } from 'redux-form/immutable'
const renderField = ({ input, field }) => {
const { type, placeholder } = field
if (type === 'text' || type === 'email' || type === 'number' || type === 'checkbox') {
return <input {...input} placeholder={placeholder} type={type} />
} else if (type === 'select') {
const { options } = field
return (
<select name={field.name} onChange={input.onChange}>
{options.map((option, index) => {
return <option key={index} value={option.value}>{option.label}</option>
})}
</select>
)
} else {
return <div>Type not supported.</div>
}
}
const SimpleForm = ({ handleSubmit, fields }) => {
return (
<div>
{fields.map(field => (
<div key={field.name}>
<Field
name={field.name}
component={renderField}
field={field}
/>
</div>
))}
<div onClick={handleSubmit}>Submit</div>
</div>
)
}
export default reduxForm({
form: 'simpleForm'
})(SimpleForm)
and passing fields to SimpleForm component like this:
<SimpleForm fields={fields} onSubmit={() =>{}}/>
Now it's your choice that you want to fetch fields like this from the server or just want to fetch only items and make fields like this (by passing item as the name of field) on the frontend.
By using this approach, I am able to re-use template based on given type.
If someone has a better approach to make a form dynamically, then I would love to learn that too.
Edit:
If we have to pass form name dynamically, then a small change will be required:
export default reduxForm({})(SimpleForm)
and we can pass form name while this component like this:
<SimpleForm form={'simpleForm'} fields={fields} onSubmit={() =>{}} />

you can create a component form and use it in a .map() function and pass formName as props like this...
render() {
return(
<div>
{yourDataFromServer.map((item, index) =>
<ReduxFormComp
form={`${FORM_NAMES.SIMPLE_FORM}__${index}`}
initialValues={item}
/>
)}
</div>
);
}
NOTE: when you use from initialValues for init your form, all field name should equal to your data.

Related

What is the professional way to manage lots of form input fields in ReactJS?

My React App has over 20 fields on form tag. and my working code like the following
function DriverForm() {
const [formData1, setFormData1] = useState(1);
const [formData2, setFormData2] = useState(2);
const [formData3, setFormData3] = useState(3);
const [formData4, setFormData4] = useState(4);
const [formData5, setFormData5] = useState(5);
const handleSubmit = (event) => {
event.preventDefault();
};
return (
<div className="wrapper">
<form onSubmit={handleSubmit}>
<input value={formData1} onChange={(e) => setFormData1(e.target.value)} />
<input value={formData2} onChange={(e) => setFormData2(e.target.value)} />
<input value={formData3} onChange={(e) => setFormData3(e.target.value)} />
<input value={formData4} onChange={(e) => setFormData4(e.target.value)} />
<input value={formData5} onChange={(e) => setFormData5(e.target.value)} />
<button type="submit">Submit</button>
</form>
</div>
);
}
as you see, my code has the code repeat to declare the input field state variable like const [formData5, setFormData5] = useState(5);
and At the rendering function, onChange={(e) => setFormData1(e.target.value)} was repeated lots of time.
is there any way to be simple and look professional by using json object and other?
I suppose you could make the code more DRY by combining the duplicated bits.
Single state object holding field values by input name
Single change handler to handle merging in state updates
Assign inputs a name attribute to be passed with change event
DRY solution
function DriverForm() {
const [formData, setFormData] = useState({
data1: 1,
data2: 2,
// etc...
});
const handleSubmit = (event) => {
event.preventDefault();
// handle formData
};
const handleChange = event => {
event.preventDefault();
const { name, value } = event.target;
setFormData(formData => ({
...formData,
[name]: value,
}))
}
return (
<div className="wrapper">
<form onSubmit={handleSubmit}>
<input value={formData.data1} name="data1" onChange={handleChange} />
<input value={formData.data2} name="data2" onChange={handleChange} />
// etc..
<button type="submit">Submit</button>
</form>
</div>
);
}
If you know ahead of time what the input types will be you can load them into a configuration array and map them
const fieldData = [
{
name: 'data1',
type: 'text',
},
// etc...
];
...
<form onSubmit={handleSubmit}>
{fieldData.map(({ name, type }) => (
<input
key={name{
type={type}
value={formData[name]}
name={name}
onChange={handleChange}
/>
))}
<button type="submit">Submit</button>
</form>
There are many answers to this question. However, one of the rules I like to code by is 'Everything is an array'.
I would start by creating an array of form fields. Then take those form fields, and build the initial state object to be used in the formData state hook.
const formFields = [
{ name: 'field1', type: 'text', initialValue: '1' },
{ name: 'field2', type: 'text', initialValue: '2' },
{ name: 'field3', type: 'text', initialValue: '3' },
{ name: 'field4', type: 'text', initialValue: '4' },
{ name: 'field5', type: 'text', initialValue: '5' },
];
const initalState = formFields.reduce(
(acc, next) => ({ ...acc, [next.name]: next.initalValue }),
{}
);
Then create a single handleChange handler.
const handleChange = (name, value) => {
setFormData({
...formData,
[name]: value,
});
};
And finally, map the formFields in your render function.
{formFields.map(({ name, type }) => (
<input
key={name}
name={name}
type={type}
value={formData[name]}
onChange={(e) => handleChange(e.target.value, name)}
/>
))}
Complete code:
const formFields = [
{ name: 'field1', type: 'text', initialValue: '1' },
{ name: 'field2', type: 'text', initialValue: '2' },
{ name: 'field3', type: 'text', initialValue: '3' },
{ name: 'field4', type: 'text', initialValue: '4' },
{ name: 'field5', type: 'text', initialValue: '5' },
];
const initalState = formFields.reduce(
(acc, next) => ({ ...acc, [next.name]: next.initalValue }),
{}
);
function DriverForm() {
const [formData, setFormData] = useState(initalState);
const handleChange = (name, value) => {
setFormData({
...formData,
[name]: value,
});
};
const handleSubmit = (event) => {
event.preventDefault();
};
return (
<div className="wrapper">
<form onSubmit={handleSubmit}>
{formFields.map(({ name, type }) => (
<input
key={name}
name={name}
type={type}
value={formData[name]}
onChange={(e) => handleChange(e.target.value, name)}
/>
))}
<button type="submit">Submit</button>
</form>
</div>
);
}
Working with forms in react is one of the most challenging problems to solve when developing applications. The best way to work with the form is react-hook-form. It is introduced so that the performance or latency of the react application will be improved to such a great extend. There is another way of creating a form in react is Formik.
Both Formik and React Hook Form are solving the same problem (provides a way to store form data in local state), but React Hook Form is a way of creating a form with uncontrolled components and the hooks allow it to give a better performance result than Formik.
I'll give you one simple example of react-hook-form.
import React, {useState} from "react";
import { useForm } from "react-hook-form";
function App() {
const { register, handleSubmit } = useForm();
const {data, setData} = useState({});
const onSubmit = (formData) => {
console.log(formData); // an object of form Data
setData(formData);
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input name="formInput1" ref={register} />
<input name="formInput2" ref={register} />
<input type="submit" />
</form>
);
}
When we console log the form data we get an object of form input.
>console
object{
formInput1: "your value",
formInput2: "your 2nd value"
}
You can store this object in a local state or in a database through API call.
I'll recommend you to learn both Formik and React hook form then you will be able to differentiate between them. Yes, react-hook-form is the best way to create a form in react in terms of performance. Formik lets you easy to understand and create a form in one go.
Others have given the best example of creating a react form without using formik and react hook form.
import React, { useState } from 'react'
const App=()=>{
const[fullname, setFullName]=useState({
fname:"",
lname:"",
email:"",
phone:""
});
const inputEvent=(event)=>{
// const value = event.target.value;
// const name = event.target.name;
const {name,value}=event.target;
setFullName((preValue)=>{
console.log(preValue)
console.log(value)
return{
...preValue,//gets the previous value
[name]:value//sets the value to the field that is getting changed
}
})
}
const submits=(event)=>{
event.preventDefault();
alert('Form has been submitted')
}
return(
<>
<div>
<form onSubmit={submits}>
<div>
<h1>Hello {fullname.fname} {fullname.lname}</h1>
<div className='container'>
<p>{fullname.email}</p>
</div>
{/* <p>{fullname.phone}</p> */}
<input type='text'
placeholder='Enter Your Name'
onChange={inputEvent}
name='fname'
value={fullname.fname}
/>
<input type='text'
placeholder='Enter Your Last Name'
onChange={inputEvent}
name='lname'
value={fullname.lname}
/>
<input type='text'
placeholder='Enter Your Email'
onChange={inputEvent}
name='email'
value={fullname.email}
/>
<input type='phone'
placeholder='Enter Your Phone Number'
onChange={inputEvent}
name='phone'
value={fullname.phone}
/>
<button type='submit'>Submit</button>
</div>
</form>
</div>
</>
)
};
export default App;
This how handle too much of inputs in a form you can extend it in your desired way
What you should do is just replace the names and values in your way like formData1

Returning correct value using react-select and react-hook-form

I'm using react-hook-forms Controller api around AsyncSelect from react-select to load options as the user types from an external API. Everything works fine except the returned value is coming back as the string "[object Object]" instead of the fullName property from the object.
My component:
<Controller
control={control}
name="businessCategory"
as={
<AsyncSelect
className="react-select-container"
loadOptions={v => handleAutocompleteLookup(v)}
onChange={handleCategoryInputChange}
getOptionLabel={option => option.name}
getOptionValue={option => option.fullName}
/>
}
/>
My handleChange function. SetValue is from react-hook-form:
const handleCategoryInputChange = newValue => {
return setValue('businessCategory', newValue, true);
};
Any my data is an array of objects with the following shape:
{
fullName: "DJ service"
id: "gcid:dj"
name: "DJ service"
publisher: "GMB"
}
Any clues on this would be appreciated, thank you!
Update your code in following way
In your import
import { useForm, Controller } from 'react-hook-form';
import Select from 'react-select';
In your hook component
function Yourcomponent(props){
const methods = useForm();
const { handleSubmit } = methods;
const options = [
{ value: '1', label: 'Apple'},
{ value: '2', label: 'Ball'},
{ value: '3', label: 'Cat'},
];
const default_value = 1; // you can replace with your default value
// other codes of the component
function submitHandler(formData){
// values are available in formData
}
return(
<div>
{* other part of your component *}
<form onSubmit={handleSubmit(submitHandler)} >
{* other part of your form *}
<Controller
control={methods.control}
defaultValue={default_value}
name="field_name_product"
render={({ onChange, value, name, ref }) => (
<Select
inputRef={ref}
classNamePrefix="addl-class"
options={options}
value={options.find(c => c.value === value)}
onChange={val => onChange(val.value)}
/>
)}
/>
{* other part of your form *}
</form>
{* other part of your component *}
</div>
)
}
For multi-select (works with react-hook-form v7):
import Select from "react-select";
import { useForm, Controller } from "react-hook-form";
const {
control
} = useForm();
<Controller
control={control}
defaultValue={options.map(c => c.value)}
name="options"
render={({ field: { onChange, value, ref }}) => (
<Select
inputRef={ref}
value={options.filter(c => value.includes(c.value))}
onChange={val => onChange(val.map(c => c.value))}
options={options}
isMulti
/>
)}
/>
I made it work like this:
const options = [
{value: '', label: ''}
]
import { useForm, Controller } from "react-hook-form";
import { ErrorMessage } from "#hookform/error-message";
import Select from "react-select";
const methods = useForm();
<section>
<label>Label</label>
<Controller
as={Select}
name="Name"
options={options}
isMulti
control={methods.control}
/>
<ErrorMessage errors={methods.errors} name="Name" />
</section>
well, actually most of these answers don't work for situations where you have a custom onChange function. The trick (seems like a bug) is to set the "onChange(val.value)" inline first and then set your state variable. Here is the full code I have that works;
import { useForm, Controller } from "react-hook-form";
const {
register,
control,
formState: { errors },
handleSubmit,
} = useForm();
const handleChangeType = (option) => {
setItemType(option);
var options = getOptions(option.value);
setList(options);
setGender(null);
};
<Controller
control={control}
name="itemType"
rules={{
required: {
value: assetType.value == "item",
message: "Item type is required.",
},
}}
render={({ field: { onChange, value, ref, name } }) => (
<Select
className={"react-select"}
classNamePrefix={"react-select"}
placeholder={"Item type"}
options={itemTypeList}
onChange={val => {
onChange(val.value);
handleChangeType(val);
}}
/>
)}
/>
{errors.item?.message && <div class="validationText">{errors.item?.message}</div>}
import Select from "react-select";
import { useForm, Controller } from "react-hook-form";
const options = [
{ value: '1', label: 'Apple'},
{ value: '2', label: 'Ball'},
{ value: '3', label: 'Cat'},
];
const {control} = useForm();
<Controller
control={control}
name="AnyName"
render={({ field: { onChange, value, name, ref } }) => (
<Select
inputRef={ref}
classNamePrefix="addl-class"
options={options}
value={options.find((c) => c.value === value)}
onChange={(val) => onChange(val.map((c) =>c.value))}
isMulti
/>
)}
/>
Fixed this by approaching it with a custom register via react-hook-form as seen here:
https://react-hook-form.com/get-started#Registerfields
I wanted to post what worked for me. I used react-select, react-hook-form, and #hookform/error-message:
I created a function as follows
const handleCategoryInputChange = (newValue: any) => {
console.log(newValue.value);
return setValue('contract', newValue.value);
};
My react select looks like this:
<Controller
name="contract"
control={control}
rules={{ required: true }}
render={({ field: { onChange, value, name, ref } }) => (
<ReactSelect
// value={contractData.find((c) => c.value === value)}
// onChange={(val) => onChange(val)}
onChange={handleCategoryInputChange}
options={contractData}
ref={ref}
name={name}
defaultValue={contractData[0]}
theme={customTheme}
isSearchable={false}
className="block w-full min-w-0 flex-1 sm:text-sm"
/>
)}
/>
<ErrorMessage errors={errors} name="contract" message="Select a Contract" />
I don't think my className is working properly you can ignore that part. It is working for my specific set up though lol. The commented out code did not work the way I wanted because when i console logged the data I got it as follow:
contract: {label: 'contract name', value: 'contract name'}
optionPeriods: "dfd"
performanceEndDate: "2022-12-08"
performanceStartDate: "2022-12-08"
proposalDueDate: "2022-12-08T12:54"
requirements: "dfd"
trackingNumber: "dfd"
so I commented out that specific solution and did it the way you see now and i get the exact data i want for my contract as you can see below:
contract: "contract name"
optionPeriods: "dfd"
performanceEndDate: "2022-12-08"
performanceStartDate: "2022-12-08"
proposalDueDate: "2022-12-08T12:54"
requirements: "dfd"
trackingNumber: "dfd"
I hope this helps

How to reset a react-select single-input with Formik with reset button

I am relatively new to React and especially new to both react-select and Formik. I have a form that has an Input component and three Select components. The input as well as the two selects that use isMulti for multiple selected options at once clear just fine when I use just a basic reset button, but the single select component does not. If I check what the values are they are empty, but the UI does not reflect this change. I have tried:
utilizing resetForm(), setting it to the initialValues as well as an empty object.
using onReset and implicitly calling resetForm from there.
using a few different variations of setFieldValue
I thought it might be the way my initialValues were set up, but at this point I am just going in circles and hoping a more seasoned eye can pick up on this.
(PS- the example in the docs shows you how to use React-Select with Formik with a reset button, but it does not give an example of a non-multi select.)
The single select has a name of 'paid', and I have include the object which I believe is correct using a value and a label property
simplified sandbox. desired behavior: clicking 'reset' will reset the option to the initialValues and show the placeholder text in the UI.
https://codesandbox.io/s/peh1q
const costOptions = [
{ value: 'true', label: 'Paid' },
{ value: 'false', label: 'Free' },
];
Resources.propTypes = {
initialValues: shape({
category: array,
q: string,
languages: array,
paid: string,
}),
};
Resources.defaultProps = {
initialValues: {
category: [],
q: '',
languages: [],
paid: '',
},
};
<Formik
enableReinitialize
initialValues={initialValues}
onSubmit={(values, actions) => {
handleSubmit(values, actions);
actions.setSubmitting(true);
}}
>
{({ isSubmitting }) => (
<Form>
<Field
data-testid={RESOURCE_SEARCH}
disabled={isSubmitting}
type="search"
name="q"
label="Search Keywords"
component={Input}
/>
<div className={styles.formContainer}>
<div className={styles.selectColumn}>
<Field
isDisabled={isSubmitting}
isMulti
placeholder="Start typing a category..."
label="By Category"
name="category"
options={allCategories}
component={Select}
/>
</div>
<div className={styles.selectColumn}>
<Field
isDisabled={isSubmitting}
placeholder="Resource cost..."
label="By Cost"
name="paid"
options={costOptions}
component={Select}
/>
</div>
<div className={styles.selectColumn}>
<Field
isDisabled={isSubmitting}
placeholder="Start typing a language..."
isMulti
label="By Language(s)"
name="languages"
options={allLanguages}
component={Select}
/>
</div>
</div>
<div className={styles.buttonGroup}>
<Button disabled={isSubmitting} type="submit">
Search
</Button>
<Button disabled={isSubmitting} type="reset">
Reset
</Button>
</div>
</Form>
)}
</Formik>
So nothing I needed to fix was actually in the code I posted (learning point taken) but it was in the codesandbox.
Select component being used in Formik looks like this:
import React from 'react';
import {
arrayOf,
bool,
func,
number,
object,
objectOf,
oneOfType,
shape,
string,
} from 'prop-types';
import { ErrorMessage } from 'formik';
import Alert from 'components/Alert/Alert';
import Label from 'components/Form/Label/Label';
import ThemedReactSelect from './ThemedReactSelect';
import styles from './Select.module.css';
Select.propTypes = {
field: shape({
name: string.isRequired,
value: oneOfType([string.isRequired, arrayOf(string.isRequired).isRequired]),
}).isRequired,
form: shape({
// TODO: Resolve why multiselects can end up with touched: { key: array }
// see ThemedReactSelect as well
// touched: objectOf(bool).isRequired,
touched: object.isRequired,
errors: objectOf(string).isRequired,
setFieldTouched: func.isRequired,
setFieldValue: func.isRequired,
}).isRequired,
hasValidationStyling: bool,
id: oneOfType([string, number]),
isLabelHidden: bool,
isMulti: bool,
label: string.isRequired,
options: arrayOf(shape({ label: string.isRequired, value: string.isRequired }).isRequired)
.isRequired,
};
Select.defaultProps = {
hasValidationStyling: true,
id: undefined,
isLabelHidden: false,
isMulti: false,
};
export default function Select({
field: { name, value: fieldValue },
form: { errors, setFieldTouched, setFieldValue, touched },
hasValidationStyling,
id,
isLabelHidden,
isMulti,
label,
options,
...props // disabled, placeholder, etc.
}) {
/**
* #description handle changing of non-multi select
* #param {string} selected
*/
const onChangeSingle = selected => {
setFieldValue(name, selected.value);
};
/**
* #description handle changing of multi select
* #param {string[]} selectedArray
*/
const onChangeMulti = selectedArray => {
if (selectedArray) {
setFieldValue(
name,
selectedArray.map(item => item.value),
);
} else {
setFieldValue(name, []);
}
};
/**
* #description Return the selected value as a string
* #returns {string}
*/
const getValueFromSingle = () => {
return options.find(option => option.value === fieldValue);
};
/**
* #description Return an array of selected values for multi selects
* #returns {string[]}
*/
const getValueFromMulti = () => {
return options.filter(option => fieldValue.includes(option.value));
};
const handleBlur = () => {
setFieldTouched(name);
};
const hasErrors = Boolean(errors[name]);
// handlers and value depend on whether or not select allows for multiple selections.
const value = isMulti ? getValueFromMulti() : getValueFromSingle();
const onChangeHandler = isMulti ? onChangeMulti : onChangeSingle;
return (
<div className={styles.field}>
<Label for={name} isHidden={isLabelHidden}>
{label}
</Label>
<div className={styles.selectFeedbackGrouping}>
<ThemedReactSelect
{...props}
hasErrors={hasErrors}
hasValidationStyling={hasValidationStyling}
isTouched={touched[name]}
id={id || name}
isMulti={isMulti}
name={name}
onBlur={handleBlur}
onChange={onChangeHandler}
options={options}
value={value}
/>
<ErrorMessage
name={name}
render={message => {
return hasErrors ? (
<Alert className={styles.errorMessage} type="error">
{message}
</Alert>
) : null;
}}
/>
</div>
</div>
);
}
Firstly, handle the null value that gets passed in handleOnChange when an input has isClearable={true} and you click the 'X' to clear the select
const onChangeSingle = selected => {
setFieldValue(name, selected === null ? '' : selected.value);
};
Then, give a fallback for the field value (in the ThemedReactSelect above)
<ThemedReactSelect
{...props}
hasErrors={hasErrors}
hasValidationStyling={hasValidationStyling}
isTouched={touched[name]}
id={id || name}
isMulti={isMulti}
name={name}
onBlur={handleBlur}
onChange={onChangeHandler}
options={options}
value={value || ''}
/>
and now the single selects work just like the multis when form is reset.
Have you tried adding the isClearable prop to the single value dropdown?
<Formik
enableReinitialize
initialValues={initialValues}
onSubmit={(values, actions) => {
handleSubmit(values, actions);
actions.setSubmitting(true);
}}
>
{({ isSubmitting }) => (
<Form>
//...Other Formik components
<div className={styles.selectColumn}>
<Field
isClearable={true} // <-- added this
isDisabled={isSubmitting}
placeholder="Resource cost..."
label="By Cost"
name="paid"
options={costOptions}
component={Select}
/>
</div>
<div className={styles.selectColumn}>
<Field
isDisabled={isSubmitting}
placeholder="Start typing a language..."
isMulti
label="By Language(s)"
name="languages"
options={allLanguages}
component={Select}
/>
</div>
</div>
<div className={styles.buttonGroup}>
<Button disabled={isSubmitting} type="submit">
Search
</Button>
<Button disabled={isSubmitting} type="reset">
Reset
</Button>
</div>
</Form>
)}
</Formik>

How to integrate React Rating w Redux Form

I'm interested in using React Rating to allow my users to provide 1-5 star reviews.
The Rating component renders fine like so:
<Rating />
I would like this Rating ability to appear within react redux-form. How can I integrate Rating within my existing form which has fields like so:
let fields = {}
const fieldoptions = {
type: 'select',
options: [
{},
{ label: '1', value: '1' },
{ label: '2', value: '2' },
{ label: '3', value: '3' },
{ label: '4', value: '4' },
{ label: '5', value: '5' },
]
};
....
const renderField = ({input, field, label, meta: {submitFailed, touched, error, pristine}}) => {
const { type, placeholder } = field
if (type === 'text' || type === 'email' || type === 'number' || type === 'checkbox') {
return <input {...input} placeholder={placeholder} type={type} />
} else if (type === 'select') {
const { options } = field
return (
<div className={classNames("form-group", {
"has-danger": (submitFailed && error) || (!pristine && touched && error),
"has-success": !pristine && touched && !error
})}>
<label>{field.name}</label>
<div>
<select name={field.skill_id} onChange={input.onChange} className={touched ? (error ? "form-control form-control-danger" : "form-control form-control-success") : "form-control"}>
{options.map((option, index) => {
return <option key={index} value={option.value}>{option.label}</option>
})}
</select>
{touched && error && <span className="form-control-feedback">{label} {error}</span>}
</div>
</div>
)
} else {
return <div>Type not supported.</div>
}
}
{this.props.fields.map(field => (
<div key={field.skill_id}>
<Field
name={ 'skill_id_' + field.skill_id }
component={renderField}
field={field}
/>
</div>
))}
You can integrate react-rating with redux form as shown below. Working sample at https://jsfiddle.net/sherin81/d82a1tao/ - The values are logged in console on click on the submit button.
class Page extends Component {
constructor(props) {
super(props)
this.renderField = this.renderField.bind(this)
}
renderField({ input, type }) {
if(type=== 'text') {
return (<input {...input} type={type} />)
} else {
return (<div><Rating {...input} initialRate={parseInt(input.value)} /></div>)
}
}
render() {
const { handleSubmit, onSubmit } = this.props
return (
<div>
<Field
name="rating"
component={this.renderField}
/>
<Field
name="name"
type="text"
component={this.renderField}
/>
<button type="submit" onClick={handleSubmit(onSubmit)}>Submit</button>
</div>
)
}
}
const MyTextFields = reduxForm({
form: 'Page'
})(Page)
The initial values can be set as shown below.
<MyTextFields initialValues={{ rating: 2, name: 'test' }} onSubmit={(values) => console.log(values)} />

Selected option value is empty while posting the data in react js

I am using react-select for select dropdown. I got the selected option value in onchange. While submitting the data on the signup form, the selected option value is always empty. How to get the selected option value in form handle submit submit like name and password.
class addAtribute extends Component {
handleFormSubmit({ name, password,role }) {
this.props.signup({ name, password, role});
}
constructor(props){
super(props);
this.state={value:''};
// this.state={};
}
render(){
const { handleSubmit, fields: {name, password,role }} = this.props;
return(
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<div className="login" id="login" >
<div className="col-md-12">
<input placeholder="Password" id="pwd" className="login-password form-control" type="password" {...password} />
<label for="dropdown-custom-1" >Select the Role</label>
<Select value={this.state.value} options={options}
onChange={event => this.setState({value:event.value})} {...role} /> </div>
<button action="submit " className="btn btn-block"><div action="submit" className="login-submit ">Update</div></button>
);}}
var options = [
{ value: '1', label: 'Admin'},
{ value: '2', label: 'Manager' },
{ value: '3', label: 'Editor' }];
function mapStateToProps(state){
return {auth: state.auth}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({ signup }, dispatch);
}
export default reduxForm({
form: 'signup',
fields: ['name', 'password','role'},mapStateToProps,mapDispatchToProps)(addAtribute);
You can simply write
<form onSubmit={this.handleFormSubmit.bind(this)}>

Resources