How to properly set default values using redux-forms?

diegoaguilar picture diegoaguilar · Feb 22, 2017 · Viewed 7.7k times · Source

Using React with redux-forms, I got following component, it's a form where 3 input fields might get values if the query string include the values.

I'm using initialize method for setting:

initialize({
  firstname: query.firstname,
  lastname: query.lastname,
  birthday: query.dob
});

And that fills the fills, however I got two main issues:

  • The submit button keeps disabled
  • The fields are not editable.

I tried to set a fix for the submit button by testing the invalid prop, but didn't work.

How can I fix and cope those issues?

This is the whole component code:

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { browserHistory } from 'react-router';
import { reduxForm, Field, SubmissionError } from 'redux-form'
import { RaisedButton, Paper, TextField } from 'material-ui';

import * as actionsAuth from '../redux/modules/auth';
import { createValidator, required, email } from '../utils/validation';
import FieldTextField from '../components-form/FieldTextField';


const styles = {
    root: {
        display: 'flex',
        flexWrap: 'wrap',
        justifyContent: 'space-around',
        paddingTop: 50
    },
    paper: {
        padding: 20,
        maxWidth: 500
    },
    field: {
        width: '100%'
    },
    button: {
        width: '100%',
        marginTop: 10
    }
};

const validate = createValidator({
    firstname: [],
    lastname: [],
    birthday: []
});

class LoginPage extends Component {

    constructor(props) {
        super();
        this.submit = this.submit.bind(this);
    }

    static propTypes = {
        patientChatLogin: PropTypes.func.isRequired
    };

    submit(values) {
        const { user } = this.props;
        let dob = values.birthday.split('-');
        let data = {
            _id: user.id,
            firstname: values.firstname,
            lastname: values.lastname,
            dob: {
                year: dob[0],
                month: dob[1],
                day: dob[2]
            }
        }
        const { patientChatLogin } = this.props;

        return patientChatLogin(data)
            .then(this.onSubmitSuccess, this.onSubmitError);
    }

    onSubmitSuccess(patient) {
        browserHistory.push(`/chat/${patient.id}`);
    }

    onSubmitError(rejection) {
        throw new SubmissionError({ auth: rejection.error, _error: 'Login failed!' });
    }

    ///////////////////
    // render

    render() {
        return (
            <div style={styles.root}>
                {this.renderForm()}
            </div>
        );
    }

    renderForm() {
        const { handleSubmit, initialize, location: {query} } = this.props;
        if (query.firstname && query.firstname !== 'undefined' &&
            query.lastname && query.lastname !== 'undefined' &&
            query.dob && query.dob !== 'undefined') {
            initialize({
              firstname: query.firstname,
              lastname: query.lastname,
              birthday: query.dob
            });
        }
        return (
            <form
                onSubmit={handleSubmit(values => this.submit(values))}
            >
                <Paper style={styles.paper} zDepth={1}>
                    {this.renderFieldFirstName()}
                    {this.renderFieldLastName()}
                    {this.renderFieldBirthday()}
                    {this.renderSubmitButton()}
                </Paper>
            </form>
        );
    }

    renderFieldFirstName() {
        // TODO:
        // Set default as redux-form requires it
        return (
            <Field
                autoFocus
                style={styles.field}
                name="firstname"
                floatingLabelText="First Name"
                component={FieldTextField}
                required
            />
        );
    }

    renderFieldLastName() {
        return (
            <Field
                style={styles.field}
                name="lastname"
                floatingLabelText="Last Name"
                component={FieldTextField}
                required
            />
        );
    }

    renderFieldBirthday() {
        return (
            <Field
                style={styles.field}
                type="date"
                name="birthday"
                floatingLabelText = "Date of Birth"
                floatingLabelFixed={true}
                component={FieldTextField}
                required
            />
        );
    }

    renderSubmitButton() {
        const { pristine, submitting, invalid } = this.props;
        return (
            <RaisedButton
                style={styles.button}
                type="submit"
                label="Enter secure chat"
                secondary
                disabled={ pristine || submitting ||  invalid }
            />
        );
    }
}

export default connect(state => ({
        user: state.auth.user,
}), {
        ...actionsAuth,
    })
    (reduxForm({
        form: 'AuthenticatePatientForm',
        validate,
    })(LoginPage));

Answer

Andy_D picture Andy_D · Feb 22, 2017

You're not able to edit the fields because you're initializing on every render if those props are present. To use initialize, you would want to do that in componentDidMount rather than in your render method.

An alternative approach would be to wrap the form component and supply initialValues based on those props.

const Wrapper = ({ location: { query }, ...props }) => {
  class LoginPage extends Component {
    ...
  }
  const WrappedForm = reduxForm({
    form: 'the-form',
    validate,
    initialValues: {
      firstname: query.firstname,
      lastname: query.lastname,
      birthday: query.dob
    }
   })(LoginPage);
   return <WrappedForm {...props} />;
 }