Redux form defaultValue - javascript

How to set defaultValue to input component?
<Field name={`${prize}.rank`} defaultValue={index} component={Input} type='text'/>
I tried like above but my fields are empty. I'm trying to create fieldArray (dynamic forms):
{fields.map((prize, index) =>
<div key={index} className="fieldArray-container relative border-bottom" style={{paddingTop: 35}}>
<small className="fieldArray-title marginBottom20">Prize {index + 1}
<button
type="button"
title="Remove prize"
className="btn btn-link absolute-link right"
onClick={() => fields.remove(index)}>Delete</button>
</small>
<div className="row">
<div className="col-xs-12 col-sm-6">
<Field name={`${prize}.rank`} defaultValue={index} component={Input} type='text'/>
<Field name={`${prize}.prizeId`} defaultValue={index} component={Input} type='text'/>
<Field
name={`${prize}.name`}
type="text"
component={Input}
label='Prize Name'/>
</div>
<div className="col-xs-12 col-sm-6">
<Field
name={`${prize}.url`}
type="text"
component={Input}
label="Prize URL"/>
</div>
<div className="col-xs-12">
<Field
name={`${prize}.description`}
type="text"
component={Input}
label="Prize Description" />
</div>
</div>
</div>
)}

On redux forms you can call initialize() with an object of values like so:
class MyForm extends Component {
componentWillMount () {
this.props.initialize({ name: 'your name' });
}
//if your data can be updated
componentWillReceiveProps (nextProps) {
if (/* nextProps changed in a way to reset default values */) {
this.props.destroy();
this.props.initialize({…});
}
}
render () {
return (
<form>
<Field name="name" component="…" />
</form>
);
}
}
export default reduxForm({})(MyForm);
This way you can update the default values over and over again, but if you just need to do it at the first time you can:
export default reduxForm({values: {…}})(MyForm);

This jsfiddle has an example
https://jsfiddle.net/bmv437/75rh036o/
const renderMembers = ({ fields }) => (
<div>
<h2>
Members
</h2>
<button onClick={() => fields.push({})}>
add
</button>
<br />
{fields.map((field, idx) => (
<div className="member" key={idx}>
First Name
<Field name={`${field}.firstName`} component="input" type="text" />
<br />
Last Name
<Field name={`${field}.lastName`} component="input" type="text" />
<br />
<button onClick={() => fields.remove(idx)}>
remove
</button>
<br />
</div>
))}
</div>
);
const Form = () => (
<FieldArray name="members" component={renderMembers} />
);
const MyForm = reduxForm({
form: "foo",
initialValues: {
members: [{
firstName: "myFirstName"
}]
}
})(Form);

this is my implementation using a HoC
import { Component } from 'react'
import {
change,
} from 'redux-form'
class ReduxFormInputContainer extends Component{
componentDidMount(){
const {
initialValue,
meta,
} = this.props
if(initialValue === undefined || meta.initial !== undefined || meta.dirty) return
const {
meta: { form, dispatch },
input: { name },
} = this.props
dispatch(change(form, name, initialValue))
}
render(){
const {
initialValue,
component: Compo,
...fieldProps
} = this.props
return <Compo {...fieldProps} />
}
}
function reduxFormInputContainer(component){
return function(props){
return <ReduxFormInputContainer {...props} component={component} />
}
}
export default reduxFormInputContainer
and then for exemple:
import reduxFormInputContainer from 'app/lib/reduxFormInputContainer'
InputNumericWidget = reduxFormInputContainer(InputNumericWidget)
class InputNumeric extends Component{
render(){
const props = this.props
return (
<Field component={InputNumericWidget} {...props} />
)
}
}

Related

Render component after change in another component

In my app I am adding new product. But after I click second time it appears on a list. In AddProducts I console.log the array with changed list and it had been updated. But in mu ProductList it doesnt work after click Add so I apply componentDidUpdate to react on changes. Also I use useEffect in App to react on changes sending from AddProduct but it works only I click second times.
AddProduct
function AddProducts(props) {
const [newProduct, setNewProduct] = useState({
productName: ``,
category: ``,
groceries: false,
});
const [newList, setNewList] = useState(props.productsToDisplay);
function handleChange(event) {
event.preventDefault();
setNewProduct({
...newProduct,
[event.target.name]:
event.target.type === "checkbox"
? event.target.checked
: event.target.value,
});
}
function handleAddNewProduct() {
const addProduct = newList.concat([
{
nazwa: newProduct.productName,
kategoria: newProduct.category,
produktSpozywczy: newProduct.groceries,
},
]);
setNewList(addProduct);
props.sendNewProductsToParent(newList);
}
return (
<div className={styles.Wrapper}>
{console.log(newList)}
<p>Add products</p>
<input
name="productName"
value={newProduct.productName}
onChange={handleChange}
></input>
<input
name="category"
value={newProduct.category}
onChange={handleChange}
></input>
<input
name="groceries"
type="checkbox"
value={newProduct.groceries}
onChange={handleChange}
></input>
<p>Is it groceries?</p>
<button onClick={handleAddNewProduct}>Add new product</button>
</div>
);
}
ProductList
class ProductsList extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className={commonColumnsStyles.App}>
{console.log(this.props.productsToDisplay)}
<header className={commonColumnsStyles.AppHeader}>
<p>Products list</p>
<ul>
{this.props.productsToDisplay.map((currProduct, index) => (
<li key={index} onClick={() => this.addProduct(index)}>
{currProduct.nazwa}
</li>
))}
</ul>
</header>
</div>
);
}
}
function App() {
const [resultToDisplay, setResultToDisplay] = useState(``);
const [newProductsList, setNewProductsList] = useState(produkty);
return (
<div className={styles.appWrapper}>
{console.log(newProductsList)}
<AddProducts
productsToDisplay={produkty}
sendNewProductsToParent={setNewProductsList}
/>
<div className={styles.columnsWrapper}>
<ProductsList
productsToDisplay={newProductsList}
sendAddedProductsToParent={setResultToDisplay}
/>
</div>
</div>
);
}
Solution for community:
AddProduct
function AddProducts(props) {
const [newProduct, setNewProduct] = useState({
productName: ``,
category: ``,
groceries: false,
});
function handleChange(event) {
event.preventDefault();
setNewProduct({
...newProduct,
[event.target.name]:
event.target.type === "checkbox"
? event.target.checked
: event.target.value,
});
}
function handleAddNewProduct() {
const addProduct = {
nazwa: newProduct.productName,
kategoria: newProduct.category,
produktSpozywczy: newProduct.groceries,
};
props.sendNewProductToParent((listOfPrimiaryProducts) => [
...listOfPrimiaryProducts,
addProduct,
]);
}
return (
<div className={styles.Wrapper}>
<p>Add products</p>
<input
name="productName"
value={newProduct.productName}
onChange={handleChange}
></input>
<input
name="category"
value={newProduct.category}
onChange={handleChange}
></input>
<input
name="groceries"
type="checkbox"
value={newProduct.groceries}
onChange={handleChange}
></input>
<p>Is it groceries?</p>
<button onClick={handleAddNewProduct}>Add new product</button>
</div>
);
}
export default AddProducts;
ProductList
class ProductsList extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className={commonColumnsStyles.App}>
<header className={commonColumnsStyles.AppHeader}>
<p>Products list</p>
<ul>
{this.props.productsInShop.map((currProduct, index) => (
<li key={index} onClick={() => this.addProduct(index)}>
{currProduct.nazwa}
</li>
))}
</ul>
</header>
</div>
);
}
}
export default ProductsList;
App
function App() {
const [productsList, setProductsList] = useState(produkty);
return (
<div className={styles.appWrapper}>
<AddProducts sendNewProductToParent={setProductsList} />
<div className={styles.columnsWrapper}>
<ProductsList
productsInShop={productsList}
/>
</div>
</div>
);
}
export default App;

Reactjs Dynamic Form Getting Error OnChnage input value?

I am created a dynamic form in react.js but i can not type anything value in input because onchnage function not working i don't know why i tried a lot of times but i am getting failed and adding form and deleting form is working all right only input value not working here is my code and codesandbox link https://codesandbox.io/s/reactdynamicform-02cho .
import React, { Component } from "react";
import "bootstrap/dist/css/bootstrap.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputFields: [
{
firstName: "",
lastName: ""
}
]
};
}
handleAddFields = () => {
const values = this.state.inputFields;
values.push({ firstName: "", lastName: "" });
this.setState({
values
});
};
handleRemoveFields = index => {
const values = this.state.inputFields;
values.splice(index, 1);
this.setState({
values
});
};
async onChange(e, index) {
if (
["firstName","lastName"].includes(e.target.name)
) {
let cats = [...this.state.inputFields];
cats[index][e.target.name] = e.target.value;
await this.setState({
cats
});
}else{
this.setState({ [e.target.name]: e.target.value.toUpperCase() });
}
console.log(this.state.inputFields);
}
handleSubmit = e => {
e.preventDefault();
console.log("inputFields", this.state.inputFields);
};
render() {
return (
<>
<h1>Dynamic Form Fields in React</h1>
<form onSubmit={this.handleSubmit.bind(this)}>
<div className="form-row">
{this.state.inputFields.map((inputField, index) => (
<div key={`${inputField}~${index}`}>
<div className="form-group col-sm-6">
<label htmlFor="firstName">First Name</label>
<input
type="text"
className="form-control"
id="firstName"
name="firstName"
value={inputField.firstName}
onChange={this.onChange.bind(index)}
/>
</div>
<div className="form-group col-sm-4">
<label htmlFor="lastName">Last Name</label>
<input
type="text"
className="form-control"
id="lastName"
name="lastName"
value={inputField.lastName}
onChange={this.onChange.bind(index)}
/>
</div>
<div className="form-group col-sm-2">
<button
className="btn btn-link"
type="button"
onClick={() => this.handleRemoveFields(index)}
>
-
</button>
<button
className="btn btn-link"
type="button"
onClick={() => this.handleAddFields()}
>
+
</button>
</div>
</div>
))}
</div>
<div className="submit-button">
<button
className="btn btn-primary mr-2"
type="submit"
// onSubmit={this.handleSubmit}
>
Save
</button>
</div>
<br />
<pre>{JSON.stringify(this.state.inputFields, null, 2)}</pre>
</form>
</>
);
}
}
export default App;
You approach is not the correct. Use object to contain form values
state = {
inputFields: { firstName: '', lastName: '' }
}
onChange = (e) => {
const { name, value } = e.target;
this.setState(prevState => ({ inputFields: { ...prevState.inputFields, [name]: value } }));
}
// in jsx
<input name="firstName" onChange={this.onChange} />
try this
onChange={(e)=>{this.onChange(e, index)}}
instead of
onChange={this.onChange.bind(index)}
1) Since your inputFields state is an array, you can't just call this.state.inputFields.firstName and even less inputField.firstName.
You have to call this.state.inputsFields[0].firstName.
2) If you want the index AND the event, you have to pass the onChange event like this :
<input
type="text"
className="form-control"
id="lastName"
name="lastName"
onChange={event => this.handleChange(event, index)}
/>
handleChange = (event, index) => {
console.log(event.currentTarget.value, index);
};
// output : {whatever you type} {index of the form}
// exemple : "hello 1"

Input box won't accept anything ReactJS

I have this code, but I can't make it work. The input lines simply won't accept anything. I tried searching all over the place to no avail, so i decided to finally ask the question.
P.S. I am new to react
class App extends React.Component {
state = { inputValue: [{item:'', name:''}] }
handleChange = e => {
const newValue = [...this.state.inputValue];
newValue[0][e.target.name] = e.target.value;
this.setState({inputValue: newValue});
}
render(){
return(
<div className='container jumbotron'>
<div className="row">
<div className="col">
<FirstInput handleChange={this.handleChange} inputValue={this.state.inputValue[0].name}/>
</div>
<div className="col">
<SecondInput handleChange={this.handleChange} inputValue={this.state.inputValue[0].name}/>
</div>
</div>
</div>
);
}
}
const FirstInput = (props) => (
<div>
<label>First Input</label>
<input className="form-control" onChange={props.handleChange} value={props.inputValue}/>
</div>
)
const SecondInput = ({inputValue, handleChange}) => (
<div>
<label>Second Input</label>
<input className="form-control" onChange={handleChange} value={inputValue}/>
</div>
)
ReactDOM.render(<App />, document.getElementById('root'));
Sorry, I forgot to mention that I want to maintain the array as an array of object. The goal is to have first input and second input be the same value. Meaning, changing one input will make the other input the same.
You don't have name attribute defined on your Input elements and hence the value doesn't change. Update your code to
class App extends React.Component {
state = { inputValue: [{ item: '', name: '' }, { item: '', name: '' }] }
handleChange = e => {
const newValue = [...this.state.inputValue];
newValue[0][e.target.name] = e.target.value;
this.setState({ inputValue: newValue });
}
render() {
return (
<div className='container jumbotron'>
<div className="row">
<div className="col">
<FirstInput handleChange={this.handleChange} inputValue={this.state.inputValue[0].name} />
</div>
<div className="col">
<SecondInput handleChange={this.handleChange} inputValue={this.state.inputValue[0].item} />
</div>
</div>
</div>
);
}
}
const FirstInput = (props) => (
<div>
<label>First Input</label>
<input className="form-control" name="name" onChange={props.handleChange} value={props.inputValue} />
</div>
)
const SecondInput = ({ inputValue, handleChange }) => (
<div>
<label>Second Input</label>
<input className="form-control" name="item" onChange={handleChange} value={inputValue} />
</div>
)
You are overwriting your state. inputValue: [{item:'', name:''}] is an array, and handleChange you try to assign string value.
Your code should look like this one:
class App extends React.Component {
state = {
firstInput: '',
secondInput: ''
}
handleChange = e => {
this.setState({
[e.target.name]: e.target.value;
});
}
render(){
return(
<div className='container jumbotron'>
<div className="row">
<div className="col">
<Input
label="First Input"
name="firstInput"
handleChange={this.handleChange}
inputValue={firstInput}/>
</div>
<div className="col">
<Input
label="First Input"
name="secondInput"
handleChange={this.handleChange}
inputValue={secondInput}/>
</div>
</div>
</div>
);
}
}
const Input = (props) => (
<div>
{props.label && <label>{props.label}</label>}
<input
className="form-control"
onChange={props.handleChange}
name={props.name}
value={props.inputValue}/>
</div>
)
ReactDOM.render(<App />, document.getElementById('root'));

React Redux Form: form is submiting with old values

I have a FieldArray in Redux Form that I push objects inside this array and right after that I have a callback to trigger a function to make a POST request.
When I submit the form I get the old values, because the push() method of the Redux Form is an async dispach from redux.
// Parent component
<FieldArray
name="myObjects"
component={ChildComponent}
onSubmitObjects={this.onSubmit} />
// Function
onSubmit = async () => {
const { getFormValues } = this.props;
const data = {
myObjects: getFormValues.myObjects
}
try {
// const contact = await Service.updateUser(data);
} catch (e) {
console.log(e)
}
}
I need to submit the form with the new values added in the array right after the push method.
// Function inside ChildComponent
addNewObject = () => {
const { fields, onSubmitObjects} = this.props;
fields.push({
number: 1,
name: 'Foo',
});
if (onSubmitObjects) {
onSubmitObjects(); // cb() to trigger a function in the parent component
}
}
Is there a way to call the callback with the new values right after the push method?
You should use a form with redux-form handleSubmit to wrap your FieldArray. You can optionally pass your custom submit function (to make API requests, submit validation, etc.) to handleSubmit so it'd look like this <form onSubmit={handleSubmit(this.onSubmit)}> ...
See this example from redux-form official docs:
FieldArraysForm.js
import React from 'react'
import {Field, FieldArray, reduxForm} from 'redux-form'
import validate from './validate'
const renderField = ({input, label, type, meta: {touched, error}}) => (
<div>
<label>{label}</label>
<div>
<input {...input} type={type} placeholder={label} />
{touched && error && <span>{error}</span>}
</div>
</div>
)
const renderHobbies = ({fields, meta: {error}}) => (
<ul>
<li>
<button type="button" onClick={() => fields.push()}>Add Hobby</button>
</li>
{fields.map((hobby, index) => (
<li key={index}>
<button
type="button"
title="Remove Hobby"
onClick={() => fields.remove(index)}
/>
<Field
name={hobby}
type="text"
component={renderField}
label={`Hobby #${index + 1}`}
/>
</li>
))}
{error && <li className="error">{error}</li>}
</ul>
)
const renderMembers = ({fields, meta: {error, submitFailed}}) => (
<ul>
<li>
<button type="button" onClick={() => fields.push({})}>Add Member</button>
{submitFailed && error && <span>{error}</span>}
</li>
{fields.map((member, index) => (
<li key={index}>
<button
type="button"
title="Remove Member"
onClick={() => fields.remove(index)}
/>
<h4>Member #{index + 1}</h4>
<Field
name={`${member}.firstName`}
type="text"
component={renderField}
label="First Name"
/>
<Field
name={`${member}.lastName`}
type="text"
component={renderField}
label="Last Name"
/>
<FieldArray name={`${member}.hobbies`} component={renderHobbies} />
</li>
))}
</ul>
)
const FieldArraysForm = props => {
const {handleSubmit, pristine, reset, submitting} = props
return (
<form onSubmit={handleSubmit}>
<Field
name="clubName"
type="text"
component={renderField}
label="Club Name"
/>
<FieldArray name="members" component={renderMembers} />
<div>
<button type="submit" disabled={submitting}>Submit</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
)
}
export default reduxForm({
form: 'fieldArrays', // a unique identifier for this form
})(FieldArraysForm)

how to get <Field> values in redux-form 7.0.0

class Form extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
const { Add, noteList } = this.props;
Add('this is title's value' , 'this is content's value');
}
render() {
const { handleSubmit, noteList: { list } } = this.props;
return (
<form onSubmit={handleSubmit(this.handleClick)}>
<div>
<Field className="title" name="title" component="input" type="text" />
</div>
<div>
<Field className="content" name="content" component="textarea" />
</div>
<div>
<button type="submit" onClick={(e) => { list ? this.handleClick : e.preventDefault(); }}>add</button>
</div>
</form>
);
}
}
when i click the button, i hope to get these two values into a function Add as two arguments to do something async, what should i do , help me please
The field values in handleClick function can can be obtained onSubmit as an object.
class Form extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(values) {
const { Add, noteList } = this.props;
Add(values.title , values.content);
}
render() {
const { handleSubmit, noteList: { list } } = this.props;
return (
<form onSubmit={handleSubmit(this.handleClick)}>
<div>
<Field className="title" name="title" component="input" type="text" />
</div>
<div>
<Field className="content" name="content" component="textarea" />
</div>
<div>
<button type="submit" onClick={(e) => { list ? this.handleClick : e.preventDefault(); }}>add</button>
</div>
</form>
);
}
}

Categories