awwester
awwester

Reputation: 10182

render textarea control with react-bootstrap and react-redux-form

I'm currently rendering input controls like so:

renderField = function({ input, label, name, type, meta: { touched, error, warning } }) {
    return (
      <FormGroup>
        <FormControl {...input} type={type} placeholder={label} />
        {touched && error && <span className="error-text">{error}</span>}
      </FormGroup>
    );
  }

  render() {
    const { handleSubmit, pristine, error } = this.props;

    return (
      <form onSubmit={handleSubmit(this.onSubmit)} className="profile-form">
        <Field name="first_name" component={this.renderField} type="text" label="First Name" />
        <Field name="last_name" component={this.renderField} type="text" label="Last Name" />
        <Field name="bio" component={this.renderField} type="text" label="Bio" />
        ...

        <Button bsStyle="primary" type="submit" disabled={pristine}>Save Changes</Button>
      </form>
    );
  }

I want to change the bio field to be a textarea control instead of an input. Is it possible to do this within my renderField function. I'd like to do it there instead of having to replicate for another function such as renderTextArea since that would duplicate a lot of the arguments and bootstrap markup.

I'm not seeing any examples of this in the docs or searches but maybe I'm thinking about it wrong.

Upvotes: 1

Views: 4792

Answers (2)

Orar
Orar

Reputation: 958

You could also use Control with FormControl straightaway.

export const InputFieldComponent = ({
                                     id,
                                     type,
                                     label,
                                     fieldObject,
                                     placeHolder,
                                     maxLength,
                                     srOnly,
                                     messages, validators, onChange}: Props) => (
 <FormGroup controlId={id} validationState={fieldObject.valid ? 'success' : 'error'>
   <ControlLabel srOnly={srOnly}>{label}</ControlLabel>
   <Control
     model={`.${id}`}
     type={type}
     placeHolder={ placeHolder || label }
     component={FormControl}
     maxLength={maxLength}
     validators={validators}
     onChange={onChange}
   >
   <FormControl.Feedback> <FaCheck /> </FormControl.Feedback>
   <Errors
    show="touched"
    model={`.${id}`}
    wrapper={ (v) => <HelpBlock>{v}</HelpBlock> }
    messages={messages}
   />
 </FormGroup>
);

InputFieldComponent.defaultProps = {
 messages: {},
 srOnly: false,
 type: 'text',
 maxLength: 255
}

export default InputFieldComponent;

Upvotes: 0

awwester
awwester

Reputation: 10182

thanks to @elmeister for the comment to lead in the right direction. I was missing the componentClass prop, so on the bio field I just needed to change to

<Field name="bio" component={this.renderField} type="text" label="Bio" componentClass="textarea" />

and then in my renderField method I needed to add componentClass as an argument and add that prop to the FormControl component. I didn't need to change input to field btw, i think componentClass just overrides it when passed in.

renderField = ({ input, label, name, type, componentClass, meta: { touched, error, warning } }) => {
    return (
      <FormGroup>
        <ControlLabel>{label}</ControlLabel>
        <FormControl {...input} componentClass={componentClass} type={type} placeholder={label} />
        {touched && error && <span className="error-text">{error}</span>}
      </FormGroup>
    );
  }

Upvotes: 1

Related Questions