Skip to content

Instantly share code, notes, and snippets.

@shinaisan
Last active October 28, 2017 14:30
Show Gist options
  • Save shinaisan/8220c38644302f73bffe006cca29cb78 to your computer and use it in GitHub Desktop.
Save shinaisan/8220c38644302f73bffe006cca29cb78 to your computer and use it in GitHub Desktop.
Redux Form - Field Arrays Example
import React from 'react';
import FieldArraysForm from './FieldArraysForm';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from './reducer';
import "bootstrap/dist/css/bootstrap.css";
const store = createStore(reducer);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {debug: ''};
}
handleSubmit(values) {
const self = this;
self.setState({debug: JSON.stringify(values)});
}
render() {
const onSubmit = this.handleSubmit.bind(this);
return (
<Provider store={store}>
<div>
<FieldArraysForm onSubmit={onSubmit} />
<div>
<pre>{this.state.debug}</pre>
</div>
</div>
</Provider>
);
}
}
export default App;
#!/bin/bash
NAME=redux-form-selecting-form-values
echo -n "This script runs create-react-app $NAME. Proceed? (Y/N) "
read YN
if [ x$YN != xY ]
then
echo "Bye."
exit
fi
# Delete this line only if you are sure what is done from this line on.
exit
create-react-app $NAME
cd $NAME
cp -v ../package.json .
cd src
rm -f App.* logo.svg
cp -v ../../*.js .
cd ..
yarn install
echo 'To launch the dev server, run `yarn run start`.'
import React from 'react'
import { Field, FieldArray, reduxForm } from 'redux-form'
import validate from './validate'
import {
Form,
ListGroup, ListGroupItem,
Row, Col,
Button
} from 'react-bootstrap'
import 'font-awesome/css/font-awesome.css'
import FontAwesome from 'react-fontawesome'
const renderField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<Col sm={2}>
<label>{label}</label>
</Col>
<Col sm={4}>
<input {...input} type={type} placeholder={label} size="40"/>
{touched && error && <span>{error}</span>}
</Col>
</div>
)
const renderHobbies = ({ fields, meta: { error } }) => (
<ListGroup>
<ListGroupItem listItem>
<Button type="button" bsStyle="primary"
onClick={() => fields.push()}>
<FontAwesome name="plus"/>{' '}Add Hobby
</Button>
</ListGroupItem>
{fields.map((hobby, index) => (
<ListGroupItem listItem key={index}>
<Button
type="button"
bsStyle="danger"
title="Remove Hobby"
onClick={() => fields.remove(index)}
>
<FontAwesome name="trash"/>{' '}Remove Hobby
</Button>
<Row>
<Field
name={hobby}
type="text"
component={renderField}
label={`Hobby #${index + 1}`}
/>
</Row>
</ListGroupItem>
))}
{error && <ListGroupItem listItem className="error">{error}</ListGroupItem>}
</ListGroup>
)
const renderMembers = ({ fields, meta: { error, submitFailed } }) => (
<ListGroup>
<ListGroupItem listItem>
<Button type="button" bsStyle="primary"
onClick={() => fields.push({})}>
<FontAwesome name="plus"/>{' '}Add Member
</Button>
{submitFailed && error && <span>{error}</span>}
</ListGroupItem>
{fields.map((member, index) => (
<ListGroupItem listItem key={index}>
<Button
type="button"
bsStyle="danger"
title="Remove Member"
onClick={() => fields.remove(index)}
>
<FontAwesome name="trash"/>{' '}Remove Member
</Button>
<h4>Member #{index + 1}</h4>
<Row>
<Field
name={`${member}.firstName`}
type="text"
component={renderField}
label="First Name"
/>
<Field
name={`${member}.lastName`}
type="text"
component={renderField}
label="Last Name"
/>
</Row>
<FieldArray name={`${member}.hobbies`} component={renderHobbies} />
</ListGroupItem>
))}
</ListGroup>
)
const FieldArraysForm = props => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<Form onSubmit={handleSubmit}>
<Row>
<Field
name="clubName"
type="text"
component={renderField}
label="Club Name"
/>
</Row>
<FieldArray name="members" component={renderMembers} />
<div>
<Button type="submit" bsStyle="primary" disabled={submitting}>
Submit
</Button>
<Button type="button" bsStyle="default" disabled={pristine || submitting} onClick={reset}>
Clear Values
</Button>
</div>
</Form>
)
}
export default reduxForm({
form: 'fieldArrays', // a unique identifier for this form
validate
})(FieldArraysForm)
{
"name": "redux-form-initialize-from-state",
"version": "0.1.0",
"private": true,
"dependencies": {
"bootstrap": "^3.3.7",
"font-awesome": "^4.7.0",
"react": "^16.0.0",
"react-bootstrap": "^0.31.5",
"react-dom": "^16.0.0",
"react-fontawesome": "^1.6.1",
"react-redux": "^5.0.6",
"redux": "^3.7.2",
"redux-form": "^7.1.2"
},
"devDependencies": {
"react-scripts": "1.0.14"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
const rootReducer = combineReducers({
form: formReducer
});
export default rootReducer;
const validate = values => {
const errors = {}
if (!values.clubName) {
errors.clubName = 'Required'
}
if (!values.members || !values.members.length) {
errors.members = { _error: 'At least one member must be entered' }
} else {
const membersArrayErrors = []
values.members.forEach((member, memberIndex) => {
const memberErrors = {}
if (!member || !member.firstName) {
memberErrors.firstName = 'Required'
membersArrayErrors[memberIndex] = memberErrors
}
if (!member || !member.lastName) {
memberErrors.lastName = 'Required'
membersArrayErrors[memberIndex] = memberErrors
}
if (member && member.hobbies && member.hobbies.length) {
const hobbyArrayErrors = []
member.hobbies.forEach((hobby, hobbyIndex) => {
if (!hobby || !hobby.length) {
hobbyArrayErrors[hobbyIndex] = 'Required'
}
})
if (hobbyArrayErrors.length) {
memberErrors.hobbies = hobbyArrayErrors
membersArrayErrors[memberIndex] = memberErrors
}
if (member.hobbies.length > 5) {
if (!memberErrors.hobbies) {
memberErrors.hobbies = []
}
memberErrors.hobbies._error = 'No more than five hobbies allowed'
membersArrayErrors[memberIndex] = memberErrors
}
}
})
if (membersArrayErrors.length) {
errors.members = membersArrayErrors
}
}
return errors
}
export default validate
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment