cheslijones
cheslijones

Reputation: 9194

Passing default values to disabled input fields, but it is preventing input into enabled fields in Redux-Forms

Been fighting with this since yesterday, but this is as close to working as I can get. Just trying to pre-populate input fields with data received from server. Seems pretty simple, but I'm missing something apparently.

While I can get the fields to populate, it pretty much locks all the fields in the form from editing--ones that aren't pre-populated and should be editable.

This a snippet of what I have so far that kinda "works". The username is one where the server could respond with a value and if does it uses renderDisabledField: it populates the field with the value and disables it so it can't be edited. Otherwise, it should be editable. The password fields on the other hand should always be editable.

componentWillReceiveProps() {
    this.props.initialize(this.props.acctVal);
}

renderField(field) {
    const { 
        placeholder,
        type,
        name,
        meta: {
            touched, 
            error 
        } 
    } = field;

    return (
        <div className='form-group'>
            <input 
                className='form-control' 
                type={type}
                placeholder={placeholder}
                {...field.input} 
            />
            <div className='text-danger'>
                {touched ? error : ""}
            </div>
        </div>
    );
}

renderDisabledField(field) {

    const { 
        type,
        name,
        placeholder,
    } = field;

    return (
        <div className='form-group'>
            <input 
                className='form-control' 
                type={type}
                placeholder={placeholder}
                disabled
                {...field.input} 
            />
        </div>
    );
}

render() {
    if (this.props.permitRender) {
        const { handleSubmit } = this.props;
        return (
            <div>
                <form onSubmit={handleSubmit(this.onSubmit.bind(this))}>

                    {this.renderAlert()}

                    <h4>Set Username</h4>
                    <p>Please enter the username you would like associated with your account. It must be at least 5 characters in length.</p>

                    <Field
                        name='username'
                        type='text'
                        placeholder='Enter Username'
                        onBlur={this.validateUsername.bind(this)}
                        component={this.props.acctVal.username ? this.renderDisabledField : this.renderField}
                    />

                    <hr />

                    <h4>Set New Password</h4>
                    <p>Type your new password twice. </p>
                    <p>It must be a minimum of 8 characters in length and contain at least:</p>
                    <ol>
                        <li>One uppercase character</li>
                        <li>One special character</li>
                        <li>One number</li>
                    </ol>

                    <Field
                        name='password1'
                        type='password'
                        placeholder='Enter New Password'
                        component={this.renderField}
                    />

                    <Field
                        name='password2'
                        type='password'
                        placeholder='Confirm Password'
                        component={this.renderField}
                    />

                    <hr />

                    <button type="submit" className="btn btn-primary">Submit</button>
                </form>
                <br />
            </div>
        );            
    } else if (!this.props.permitRender) {
        return ( 
            <Loading />
        );
    } 
}

function mapStateToProps(state) {
    return { 
        errorMessage: state.auth.error,
        permitRender: state.auth.permitRender,
        questions: state.auth.questions,
        acctVal: state.auth.acctVal
    };
}

SetupUser = reduxForm({
    form: 'setup_user',
    touchOnChange: true,
    validate
})(SetupUser);
SetupUser = connect(mapStateToProps, { checkUsername, setupUser, verifyKey })(SetupUser);
export default SetupUser;

EDIT:

Almost forgot the reducer:

import {
    ACCT_VALUES
} from '../actions/authentication';

export default function(state = {}, action) {
    switch(action.type) {
        case ACCT_VALUES:
            return { ...state, 
                acctVal: {
                    username: action.payload.data.username,
                    company: action.payload.data.company_name[0].company_name,
                    firstname: action.payload.data.first_name,
                    lastname: action.payload.data.last_name,
                    email: action.payload.data.email,
                    phone: action.payload.data.phone
                },
            };
        default:
            return state;
    }

    return state;
}

I've tried the various rendering it at different points in the life cycle:

https://reactjs.org/docs/react-component.html#the-component-lifecycle

Also tried following these through but haven't been able to get the desired results:

https://redux-form.com/6.7.0/examples/initializefromstate/

Redux form defaultValue

How to properly set default values using redux-forms?

EDIT: Going in circles and retrying stuff I have already tried.

This works in getting a value into the field, but breaks when you try passing state or props into the initialValues.

function mapStateToProps(state) {
    return { 
        errorMessage: state.auth.error,
        permitRender: state.auth.permitRender,
        questions: state.auth.questions,
        acctVal: state.auth.acctVal
    };
}

SetupUser = reduxForm({
    form: 'setup_user',
    touchOnChange: true,
    validate,
    initialValues: {username: 'test1'}
}, mapStateToProps)(SetupUser);
SetupUser = connect(mapStateToProps, { checkUsername, setupUser, verifyKey })(SetupUser);
export default SetupUser;

Get the `Cannot read property 'props' of undefined with this and about a dozen other variations:

initialValues: this.props.acctVal
initialValues: {this.props.acctVal}
initialValues: {username: this.props.acctVal.username}

Upvotes: 0

Views: 559

Answers (1)

cheslijones
cheslijones

Reputation: 9194

The things one assumes to be a minor detail that are imperative.

In this case, what I had labeled as acctVal really should have been called initialValues like the documentation says:

function mapStateToProps(state) {
    return { 
        errorMessage: state.auth.error,
        permitRender: state.auth.permitRender,
        questions: state.auth.questions,
        initialValues: state.auth.acctVal
    };
}

SetupUser = reduxForm({
    form: 'setup_user',
    touchOnChange: true,
    validate,
})(SetupUser);
SetupUser = connect(mapStateToProps, { checkUsername, setupUser, verifyKey })(SetupUser);
export default SetupUser;

Then just could get rid of the:

componentWillReceiveProps() {
    this.props.initialize(this.props.acctVal);
}

Upvotes: 1

Related Questions