I have component that renders like this:
<MyComponent
prop1Value={1}
prop1OnChange={this.handleProp1Change}
prop2Value={2}
prop2OnChange={this.handleProp2Change}
/>
So it contains two fields/values internally. How I can sync it with redux-form? <Field> component provides only one value/onChange pair...
Tried it like this:
// values comes from getFormValues(...)
<MyComponent
prop1Value={values.prop1}
prop1OnChange={this.context._reduxForm.change.bind(this.context._reduxForm, 'prop1')}
prop2Value={values.prop2}
prop2OnChange={this.context._reduxForm.change.bind(this.context._reduxForm, 'prop1')}
/>
You'll have to use connect to bind those actions.
import { change } from 'redux-form';
import { connect } from 'react-redux';
const ParentComponent = (props) => {
return <div>
<MyComponent propOneOnChange={props.change('formName', 'fieldName', 'fieldValue')} />
</div>
}
export default connect(mapStateToProps, { change })(ParentComponent);
Related
How can I change the "dashoboard" menu name in the react-admin?
By default it's name is always "Dashboard" even in the Demo
the name is Dashboard. Someone knows a way to change the name or if it is even possible to change?
At the Menu.tsx, don't call it like
<DashboardMenuItem onClick={onMenuClick} sidebarIsOpen={open} />
Instead call it like a normal menu item but pointing to the dashboard component
<MenuItemLink
to={`/`} // by default react-admin renders Dashboard on this route
primaryText="Your Text"
leftIcon={<YourIcon />}
onClick={onMenuClick}
sidebarIsOpen={open}
dense={dense}
/>
Like in that answer is showed that in the MenuItemLink has an atribute called primaryText="Your Text" that you can use in your own
<DashboardMenuItem onClick={onMenuClick} classes={classes} primaryText="Your Text" />
To change the name of the default "Dashboard" name for what you want.
So more detailed answer is:
Override layout
// in src/Admin.js
<Admin
layout={MyLayout}
title="SuperCoolProject"
theme={myTheme}
dataProvider={dataProvider}
authProvider={authProvider}
>
Use custom menu in layout. (it's not sidebar)
// in src/MyLayout.js
import React from "react";
import { Layout } from "react-admin";
import MyMenu from "./MyMenu";
const MyLayout = (props) => <Layout {...props} menu={MyMenu} />;
export default MyLayout;
Change menu so it still renders resources and add custom MenuItemLinks you need (vs. one hardcoded "dashboard")
// in src/Menu.js
import React from "react";
import { useSelector } from "react-redux";
import { useMediaQuery } from "#material-ui/core";
import { MenuItemLink, getResources } from "react-admin";
import DefaultIcon from "#material-ui/icons/ViewList";
import SettingsIcon from "#material-ui/icons/Settings";
import HomeIcon from "#material-ui/icons/Home";
import HelpIcon from "#material-ui/icons/Help";
const Menu = ({ onMenuClick, logout }) => {
const isXSmall = useMediaQuery((theme) => theme.breakpoints.down("xs"));
const open = useSelector((state) => state.admin.ui.sidebarOpen);
const resources = useSelector(getResources);
return (
<div>
<MenuItemLink
to="/home"
primaryText="Home"
leftIcon={<HomeIcon />}
onClick={onMenuClick}
sidebarIsOpen={open}
/>
{resources.map((resource) => (
<MenuItemLink
key={resource.name}
to={`/${resource.name}`}
primaryText={
(resource.options && resource.options.label) || resource.name
}
leftIcon={resource.icon ? <resource.icon /> : <DefaultIcon />}
onClick={onMenuClick}
sidebarIsOpen={open}
/>
))}
<MenuItemLink
to="/custom-route"
primaryText="Settings"
leftIcon={<SettingsIcon />}
onClick={onMenuClick}
sidebarIsOpen={open}
/>
<MenuItemLink
to="/help-center"
primaryText="Help Center"
leftIcon={<HelpIcon />}
onClick={onMenuClick}
sidebarIsOpen={open}
/>
{isXSmall && logout}
</div>
);
};
export default Menu;
Looking for some insight with the Redux Form handleSubmit function. I am following along to Set Griders course from Udemy. Everything is running smoothly until here. Other error/bugs I was able to research and solve them myself. I am really struggling to find a solution here.
singin.js
import React, { Component } from 'react'
import { reduxForm } from 'redux-form'
import { Checkbox, Form, FormField, Button, Grid, GridColumn, Input } from 'semantic-ui-react'
class SignIn extends Component {
onFormSubmitHandler({ email, password }) {
console.log('Values', email, password)
}
render() {
// this.props are brought to us by reduxForm. Allowing to grab the field inputs and submit action
const { handleSubmit, fields: { email, password } } = this.props
return (
<Grid centered columns={2}>
<GridColumn>
<Form onSubmit={handleSubmit(this.onFormSubmitHandler.bind(this))}>
<FormField>
<label>Email:</label>
<Input placeholder='Email' {...email} />
</FormField>
<FormField>
<label>Password:</label>
<Input placeholder='Password' {...password} />
</FormField>
<FormField>
<Checkbox label='I agree to the Terms and Conditions' />
</FormField>
<Button action='submit'>Sign In</Button>
</Form>
</GridColumn>
</Grid>
)
}
}
export default reduxForm({
form: 'signin',
fields: ['email', 'password']
})(SignIn)
rootReducer
import { combineReducers } from 'redux'
import SetsReducer from './SetsReducer'
import { reducer as form } from 'redux-form'
const rootReducer = combineReducers({
sets: SetsReducer,
form
})
export default rootReducer
The console.log inside onFormSubmitHandler logs: 'Values undefined undefined'
Edit: Project on GitHub
I solved the issue. The fix involved importing 'Field' from redux-form and replacing the input element with elements. Passing {Input} as the component to render
I'm trying to create an Edit form w/ semantic-ui-redux-form-fields. The forms work fine w/ a blank starting point, but for an edit form where I have initial values, I haven't been able to get it to work.
If I'm using straight redux-form, this works fine for initializing the form as long as I have a prop of initialValues passed into my form component.
Using that logic, I would think to all I would need to do is change the Field#component attribute from "input" to {Input} (/w the appropriate import). Note that I never see currentValue being passed in via props. It's not clear how this prop would ever get populated.
Props:
{initialValues: {"first_name": "Bob"}}
Working Component:
import { Form, Button } from 'semantic-ui-react'
import { reduxForm, Field} from 'redux-form'
...
return <Field component="input" type="text" name='first_name'/>
Not Working Component:
import { Form, Button } from 'semantic-ui-react'
import { reduxForm, Field} from 'redux-form'
import { Input } from 'semantic-ui-redux-form-fields'
...
return <Field component={Input} type="text" name='first_name'
currentValue={this.props.currentValue}/>
The Input component in semantic-ui-react has a defaultValue prop that I believe you should be able to use to initialize the Field with data since you are passing it the Input in it's component prop.
<Field
component={Input}
defaultValue={this.props.currentValue}
name='first_name'
type='text'
/>
I am trying to use "redux-form": "^6.7.0" with "react-bootstrap": "^0.31.0"
My Component renders nicely, but when I press Submit, what I see is an empty object.
note: I have tried wrapping the Config with connect first, and as show below, first wraping it with redux-form and then with the from react-redux connect()
Configuration.js
class Config extends Component {
render() {
const { ServerPort, UserID, PortNumber, WWWUrl, SourcePath, FMEPath, pickFile, pickFolder, handleSubmit } = this.props;
return (
<Form horizontal onSubmit={handleSubmit}>
<FormGroup controlId="serverPortBox">
<Col componentClass={ControlLabel} sm={2}>Watson Port:</Col>
<Col sm={10}>
<OverlayTrigger placement="left" overlay={(<Tooltip id="tt1">TCP port for Watson to use</Tooltip>)}>
<Field name="WatsonPort" component={FormControl}
type="number" min="1024" max="65535" placeholder={ServerPort} />
</OverlayTrigger>
</Col>
</FormGroup>
......
const CForm = reduxForm({
form: 'configuration' // a unique name for this form
})(Config);
const Configuration = connect(mapStateToProps, mapDispatchToProps)(CForm)
export default Configuration
reducers.js
import { combineReducers } from 'redux'
import { reducer as formReducer } from 'redux-form
......
const reducerList = {
GLVersion,
ServerConfig,
ServerStats,
form: formReducer
}
export default combineReducers(reducerList)
Main Package Dashboard.js
what i see in the debugger is that config is an empty object
<Panel className='configPanel'
collapsible header="Configuration"
eventKey="1"
defaultExpanded={true}>
<Configuration onSubmit={(config) => writeConfig(config)} />
</Panel>
See: https://github.com/erikras/redux-form/issues/2917
Oh, this was a great mystery. I followed the advice in https://github.com/react-bootstrap/react-bootstrap/issues/2210 and both the warning about additional props and the empty submit stopped.
It seems you have to wrap the Bootstrap in your custom component (why?, I don't know). Also make sure you custom component is a stateless funcitonal component, or after the first key press, you field will blur and lose focus.
There are some warnings in the documentation of redux-form about this.
my custom field component FieldInput
const FieldInput = ({ input, meta, type, placeholder, min, max }) => {
return (
<FormControl
type={type}
placeholder={placeholder}
min={min}
max={max}
value={input.value}
onChange={input.onChange} />
)
}
and I invoke it like this:
<Field name="ServerPort"
type='number'
component={FieldInput}
placeholder={ServerPort}
min="1024" max="65535"
/>
see also: https://github.com/erikras/redux-form/issues/1750
So now, the definition of FieldInput and Config look like this:
import React, { Component } from 'react'
import { Field, reduxForm } from 'redux-form'
import { connect } from 'react-redux'
import { Form, FormControl, FormGroup, ControlLabel, Col, Button, Tooltip, OverlayTrigger } from 'react-bootstrap'
import * as Act from '../dash/actions.js'
import FaFolderOpen from 'react-icons/lib/fa/folder-open'
import FaFileCodeO from 'react-icons/lib/fa/file-code-o'
const FieldInput = ({ input, meta, type, placeholder, min, max }) => {
return (
<FormControl
type={type}
placeholder={placeholder}
min={min}
max={max}
value={input.value}
onChange={input.onChange} />
)
}
const Config = ({ ServerPort, UserID, PortNumber, WWWUrl, SourcePath, FMEPath, pickFile, pickFolder, handleSubmit }) => {
return (
<Form horizontal onSubmit={handleSubmit}>
<FormGroup controlId="serverPortBox">
<Col componentClass={ControlLabel} sm={2}>Watson Port:</Col>
<Col sm={10}>
<OverlayTrigger placement="left" overlay={(<Tooltip id="tt1">TCP port for Watson to use</Tooltip>)}>
<Field name="ServerPort" type='number' min="1024" max="65535" component={FieldInput} placeholder={ServerPort} />
</OverlayTrigger>
</Col>
</FormGroup>
Some props required by <FormControl> are passed inside props.input from <Field>, see http://redux-form.com/6.6.3/docs/api/Field.md/#props
To pass all those props in a generic way, instead of doing it explicitly, you can use the following function:
const ReduxFormControl = ({input, meta, ...props}) => {
return <FormControl {...props} {...input} />
};
and then inside the form:
<Field component={ReduxFormControl} ... />
This way, value, onChange, etc. are all passed as expected to <FormControl>.
I've been trying to implement a form in MapsAddrForm.jsx using Redux-Form and I can't seem to change the value of my input element. When the page loads, the input element does not respond to keyboard input, and when the form field submits, it returns an empty object to the parent component DistrictFinder. Beyond these two files, I've also added form:formReducer as an argument to combineReducers much like the simple example in the Redux-Form tutorials. Is there any way to restore the ability for the DistrictFinder to receive data objects from the address form? For reference, I'm using React 15.1.0, React-redux 4.4.5, ES6, and Redux-Form 5.3.1, all compiled using Webpack.
MapsAddrForm.jsx
import React, {Component} from 'react';
import { connect } from 'react-redux';
import {reduxForm} from 'redux-form';
class MapsAddrForm extends Component {
constructor(props) {
super(props);
}
render() {
const {fields: {address,address2}, handleSubmit} = this.props;
return (
<form onSubmit={handleSubmit}>
<div>
<input type="text" placeholder="Your address" {...address}/>
</div>
<button type="submit">Submit</button>
</form>
);
}
}
export default reduxForm({
form: 'addressForm',
fields: ['address']
})(MapsAddrForm);
DistrictFinder.jsx
import React, { Component, PropTypes } from 'react'
import MapsAddrForm from './MapsAddrForm.jsx'
import { connect } from 'react-redux'
import { changeAddress } from '../actions/index.jsx'
class DistrictFinder extends Component {
constructor(props) {
super(props);
this.handleAddrSubmit = this.handleAddrSubmit.bind(this);
}
handleAddrSubmit(data) {
console.log("Address received: " + JSON.stringify(data));
}
render() {
const {address, district} = this.props
return (
<div class="GMaps">
<h1>Find your district!</h1>
<MapsAddrForm onSubmit={this.handleAddrSubmit} />
<p>My district number is: {district}</p>
</div>
);
}
}
DistrictFinder.propTypes = {
district: PropTypes.string.isRequired,
dispatch: PropTypes.func.isRequired
};
function mapStateToProps(state) {
const { district } = state.infoChange;
return {
district
};
};
export default connect(mapStateToProps)(DistrictFinder);
I ran into this as well on redux-form#6.2.0
After looking at the source for one of the examples, I noticed the call to combineReducers has an explicit key "form" to the object argument. When I added this explicit key, the fields became editable.
// Correct
const reducer = combineReducers({
form: reduxFormReducer // mounted under "form"
})
If you have an existing app, like I do, you likely have this style es6 syntax from the various redux starters.
// Incorrect: results in the witnessed bad behavior
const reducer = combineReducers({
reduxFormReducer
})
See the combineReducers call at https://github.com/erikras/redux-form/blob/master/examples/simple/src/index.js#L10
It'd be interesting to see if this could be a constant that could be passed in and leveraged by the lib. "form" feels like a easily corruptible "namespace".