Redux-form: Field value from state isn't submitted - reactjs

I have a field (source-file) in redux-form which is being updated by a change in the application state. The state value is being properly delivered to the field but when clicking submit, only the first field (name) is submitted (which I fill in interactively).
What am I doing wrong here?
import React, { Component, PropTypes } from 'react';
import { reduxForm, Field } from 'redux-form';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import * as actions from '../../actions/job_actions';
import UploadPage from './upload_page';
const renderField = field => (
<div>
<label>{field.input.label}</label>
<input {...field.input}/>
{field.touched && field.error && <div className="error">{field.error}</div>}
</div> );
class JobForm extends Component {
handleFormSubmit(formProps) {
this.props.createJob(formProps); }
render() {
const { handleSubmit } = this.props;
return (
<div>
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<label>Title</label>
<Field name="name" component={renderField} type="text" />
<label>Input File</label>
<Field name="source_file" component={() => {
return (
<div class="input-row">
<input type="text" value={this.props.uploadedFile} />
</div>
)
}} />
<button type="submit" className="btn btn-
primary">Submit</button>
</form>
</div>
);
};
}
const form = reduxForm({ form: 'JobForm' });
function mapStateToProps({uploadedFile}) { return { uploadedFile }; }
export default connect(mapStateToProps, actions)(form(JobForm));

If you want redux-form to include your field, then you'll need to render it as an actual field (as you do with your renderField).
If you don't want to treat it as an actual field, then the redux-form author suggests injecting the values from state within your submit handler. Maybe something like this:
handleFormSubmit(formProps) {
this.props.createJob({ ...formProps, source_file: this.props.uploadedFile} );
}

Related

Redux Form is not firing off submit function

I have set up a redux form but it does not seem to be firing off onSubmit the actual submitHandle function.
Please see the code below
import React, { Component } from "react";
import { connect } from "react-redux";
import { hideTransferLicenseWindow, setProgressBarValue } from "../../redux/actions/LicenseActions";
import { Field, reduxForm } from 'redux-form'
export class LicenseTransfer extends Component {
componentDidMount() {
console.log(this.props)
}
renderInput = ({ input, customValue, autoFocus }) => {
return (
<input
className="uk-input"
{...input}
value={customValue}
autoFocus={autoFocus}
/>
)
}
onFormSubmit = (values) => {
console.log('Clicked submit')
}
render() {
const { licenseOperations } = this.props;
return (
<div className="app-section transfer-license-window">
<button
onClick={() => this.props.hideTransferLicenseWindow()}
uk-close=""
className="uk-alert-close"
></button>
<form onSubmit={this.props.handleSubmit(this.onFormSubmit)}>
<div className="field">
<label>From:</label>
<Field
name="transferLicenseFromEmail"
component={this.renderInput}
customValue={this.props.userEmail}
/>
</div>
<div className="field">
<label>To:</label>
<Field
name="transferLicenseToEmail"
component={this.renderInput}
autoFocus={true}
/>
</div>
</form>
</div>
);
}
}
const transferLicenseFormWrapper = reduxForm({
form: 'transferLicense',
})(LicenseTransfer)
const mapStateToProps = (state) => {
return {
userEmail: state.user.user.email,
licenseOperations: state.licenseOperations,
};
};
export default connect(mapStateToProps, { hideTransferLicenseWindow, setProgressBarValue })(
transferLicenseFormWrapper
);
So it should log form values on submitting the form but it does not react nor gives any errors/
I have similar form set up in another component which works just fine. Spent good amount of time playing the game of finding differences but this does not makes sense to me.
Thanks
Ok I figured it out.
For those who might have the same issue, make sure to place your submit button inside the Form, if you want to be able to submit by pressing "Enter".
If you just want to submit with a mouse click on button only, it is sufficient to leave the button outside of the form (not sure if there are any other consequences).

redux form initialValues not updating state

I try to set my values in my redux-form, but the input doesn't show the value. Can somebody please help me?
This is my code.
import React from "react";
import { Field, reduxForm } from "redux-form";
import {connect} from 'react-redux';
import {renderTextField, renderField, validate, warn} from "../../../Components/Forms/renders"
class SyncValidationForm extends React.Component {
constructor(props) {
super(props);
this.state = {
errors: {}
}
}
render() {
const { handleSubmit, pristine, reset, submitting } = this.props;
return (
<form onSubmit={handleSubmit}>
<div className="col-sm-12">
<h4 className="info-text"> Let's start with the basic details</h4>
</div>
<Field name="what.title.value" type="text" component={renderField} label="Titel" />
</form>
);
}
}
SyncValidationForm = reduxForm({
form: 'insertstart',
enableReinitialize: true,
validate, // <--- validation function given to redux-form
warn
})(SyncValidationForm);
const mapStateToProps = state => {
return {
initialValues: state.items.item,
}
}
export default connect(mapStateToProps)(SyncValidationForm)
I my console log I see this by console.log(this.props);
initialValues:{what.title.value: "test"}
You need to pass the initial values as an object, so instead of
what.title.value: "test"
your state.items.item should look like:
{ what: { title: { value: "test" } } }
See here for a working example.
Always use change function to bind data in redux-form fields
componentWillMount() {
const { change } = this.props
change('basicDetails', 'sdfuhdsuiafghfudsauifhdsuifhuiads') // this will bind name with basicDetails
}
<form onSubmit={handleSubmit}>
<div className="col-sm-12">
<h4 className="info-text"> Let's start with the basic details</h4>
</div>
<Field name="basicDetails" type="text" component={renderField} label="Titel" />
</form>

How to use reduxForm() and connect() together for class component in react?

added reducer in reducer file
const reducers = {
// ... other reducers here ...
form: formReducer
};
I am using redux-form v 7.1.2 with react v 16 and using reduxForm()`` but there is alreadyconnect()` applied in this class, tried 2 approached to add both HOC in the same page but failed on both.
below is the relevant code of my files , please check and let me know what is missing ?
Using named export
renderField.jsx
import React from 'react';
const renderField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type} />
{touched && error && <span>{error}</span>}
</div>
</div>
);
export default renderField;
Register.jsx
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import { renderField } from './renderField';
class RegisterPage extends React.Component {
constructor (props) {
super(props);
this.state = {
user: {
firstName: ''
},
submitted: false
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit (values) {
this.setState({ submitted: true });
const { user } = this.state;
const { dispatch } = this.props;
dispatch(userActions.register(user));
}
render () {
const { registering } = this.props;
return (
<div className="col-md-6 col-md-offset-3">
<h2>Register</h2>
<form onSubmit={this.handleSubmit} >
<div className="form-group">
<Field
name="firstName"
type="text"
label="First Name"
className="form-control"
component={renderField}
/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary" disabled={this.pristine} >Register</button>
{ registering && <Loading /> }
<Link to="/login" className="btn btn-link">Cancel</Link>
</div>
</form>
</div>
);
}
}
below class definition , here is connect and reduxForm usage
RegisterPage = reduxForm({
form: 'register',
destroyOnUnmount: false
})(RegisterPage);
const connectedRegisterPage = connect(mapStateToProps)(RegisterPage);
export { connectedRegisterPage as RegisterPage };
App.jsx
import { RegisterPage } from '../RegisterPage';
<Route path="/register" component={RegisterPage} />
BUT this gives multiple warning in console
Failed prop type: The prop component is marked as required in
Field, but its value is undefined. in Field (created by
RegisterPage)
Warning: React.createElement: type is invalid -- expected a string
(for built-in components) or a class/function (for composite
components) but got: undefined. You likely forgot to export your
component from the file it's defined in. Check the render method of
ConnectedField.
with default export
Register.jsx
RegisterPage = reduxForm({
form: 'register'
})(RegisterPage);
const connectedRegisterPage = connect(mapStateToProps)(RegisterPage);
export { connectedRegisterPage as default };
App.jsx
import RegisterPage from '../RegisterPage';
console.log("RegisterPage", RegisterPage); // undefined
this gives no warning but display blank page in the browser
You have exported renderField as a default and imported as a named import. Correct it and it should work fine
import React from 'react';
const renderField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type} />
{touched && error && <span>{error}</span>}
</div>
</div>
);
export {renderField};

React/redux input values not showing

I am using react/redux with redux-form and for some reason the input values are not showing on my edit form.
I console.log my post and it shows that they are there, but for some reason it is not working. I will post code below.
edit component:
import React , { Component } from 'react';
import * as actions from '../../actions/posts_actions';
import { reduxForm, Field } from 'redux-form';
import {connect} from 'react-redux';
import {Link} from 'react-router-dom';
class EditPost extends Component {
componentDidMount() {
const {id} = this.props.match.params;
this.props.getOnePost(id);
}
renderField(field) {
const { meta: {touched, error} } = field;
const className = `form-group ${touched && error ? 'has-danger' : ''}`;
return (
<div className={className}>
<label><strong>{field.label}:</strong></label>
<input
className="form-control"
type={field.type}
value={field.value}
{...field.input}
/>
<div className="text-help">
{ touched ? error : ''}
</div>
</div>
)
}
onSubmit(values) {
const {id} = this.props.match.params;
this.props.updatePost(values, id, () => {
this.props.history.push(`/posts/${id}`);
});
}
render() {
const {handleSubmit} = this.props;
const {post} = this.props;
if(!post) {
return <div> Loading... </div>;
}
console.log(post);
return (
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<Field
label="Title"
name="title"
type="text"
value={post.title}
component={this.renderField}
/>
<Field
label="Content"
name="content"
type="text"
value={post.content}
component={this.renderField}
/>
<button type="submit" className="btn btn-success">Submit</button>
<Link to={`/posts/${post._id}`} className="btn btn-danger">Cancel</Link>
</form>
);
}
}
function validate(values) {
const errors = {};
if(!values.title) {
errors.title = "Enter a title!";
}
if(!values.content) {
errors.content = "Enter some content please!";
}
return errors;
}
function mapStateToProps({ posts }, ownProps) {
return { post: posts[ownProps.match.params.id] };
}
export default reduxForm({
validate,
form: 'editform'
})(connect(mapStateToProps, actions)(EditPost));
Instead of setting the value directly, pass an initialValues prop:
function mapStateToProps({ posts }, ownProps) {
const post = posts[ownProps.match.params.id]
return {
post,
initialValues: {
...post
}
};
}
remove value props from Fields in your form. So long as the properties on your Post object are the same as the name of the field you want to populate, you can just use object spread. If they are different, you'll have to map them appropriately
initialValues: {
contentField: post.content
}
<Field name="contentField" />
initial values have to be set before you use the reduxForm enhancer. Also, because I know it'll come up (and trust me, it always comes up eventually), if you want your form values to update if your model updates, you'll have add enableReinitialize: true to reduxForm's config

How to reset form on submission with Redux Form?

I'm creating a basic portfolio website, that has a Contact form section, where people can send me a message to my email via Formspree. I'm using Redux Forms for this and the form works, but I'd like to reset the form fields and add some kind of 'success' message on successful submit.
I've tried 2 methods: 1) calling this.props.resetForm() and 2) calling dispatch(reset('ContactForm'). Neither have worked.
Here is the code:
contact.js:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import { sendMail } from '../actions';
class Contact extends Component {
renderField(field) {
const { meta: { touched, error } } = field;
const className = `form-group ${touched && error && 'has-error'}`;
return (
<div className={className}>
<label>{field.label}</label>
{field.type == 'text' ?
<input
className='form-control'
type={field.type}
{...field.input}
/> :
<textarea
className='form-control'
rows='5'
{...field.input}
/>}
<div className='help-block'>
{touched && error}
</div>
</div>
);
}
onSubmit(values) {
this.props.sendMail(values, () => {
this.props.resetForm();
});
}
render() {
const { handleSubmit } = this.props;
return (
<div id='contact'>
<h1>Contact</h1>
<p>Feel free to drop me a mail. Whether it's work-related or about coding, tech, entrepreneurship, travel, football or life in general. I'm always looking to connect with other people.</p>
<div id='contact-form'>
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<Field
label='Name:'
name='name'
type='text'
component={this.renderField}
/>
<Field
label='Email:'
name='email'
type='text'
component={this.renderField}
/>
<Field
label='Message:'
name='message'
type='textarea'
component={this.renderField}
/>
<button
type='submit'
className='btn btn-primary'
>
Submit
</button>
</form>
</div>
</div>
);
}
}
function validate(values) {
const errors = {};
if (!values.name) {
errors.name = "Enter a name"
}
if (!values.email) {
errors.email = "Enter an email"
}
if (!values.message) {
errors.message = "Enter a message"
}
return errors;
}
export default reduxForm({
form: 'ContactForm',
validate
})(
connect(null, { sendMail })(Contact)
);
actions/index.js:
import axios from 'axios';
import { reset } from 'redux-form';
export const MAIL_SENT = 'MAIL_SENT';
const ROOT_URL='https://formspree.io/'
const EMAIL = 'xxxxxx#gmail.com'
export function sendMail(values) {
const request = axios.post(`${ROOT_URL}${EMAIL}`, values);
return {
type: MAIL_SENT,
payload: true
};
dispatch(reset('ContactForm'));
}
You need to add a constructor to the class contact.
class Contact extends Component {
constructor(props) {
super(props);
}
...
};
Putting dispatch(reset('ContactForm')) after return syntax, it would never get called. By the way, the action creator is supposed to be a pure function. Adding dispatch action to it is not a good idea.
Hope this help.
Use
this.props.reset()
Using this works on resetting the form after submit.

Resources