dwjohnston
dwjohnston

Reputation: 11771

Putting a customised radio button component inside a Radio Group in Material UI

I want to have a list of radio buttons, with one option being a freestyle 'Other' text box that lets the user enter their own text.

Here I have a working sandbox of everything I want to do:

https://codesandbox.io/s/r4oo5q8q5o

handleChange = event => {
    this.setState({
      value: event.target.value
    });
  };

  selectItem = item => {
    this.setState({
      selectedItem: item
    });
  };

  handleOtherChange = event => {
    this.setState({
      otherText: event.target.value
    });

    this.selectItem(
      //Todo put in right format
      this.state.otherText
    );
  };
  focusOther = () => {
    this.setState({
      value: "Other"
    });

    this.selectItem(this.state.otherText);
  };

  render() {
    const { classes, items } = this.props;
    const { value } = this.state;

    return (
      <div className={classes.root}>
        <Typography>
          {" "}
          Selected item is: {JSON.stringify(this.state.selectedItem)}
        </Typography>

        <FormControl component="fieldset" fullWidth>
          <RadioGroup value={this.state.value} onChange={this.handleChange}>
            {items.map(v => (
              <FormControlLabel
                value={v.name}
                control={<Radio />}
                label={v.name}
                key={v.name}
                onChange={() => this.selectItem(v)}
              />
            ))}

            <FormControlLabel
              value="Other"
              control={<Radio />}
              label={
                <TextField
                  placeholder="other"
                  onChange={this.handleOtherChange}
                  onFocus={this.focusOther}
                />
              }
              onChange={() => this.selectItem(this.state.otherText)}
            />
          </RadioGroup>
        </FormControl>
      </div>
    );
  }
}

Now what I want to do is make the 'Other' text box its own component.

Here's my attempt:

https://codesandbox.io/s/ryomnpw1o

export default class OtherRadioButton extends React.Component {
  constructor() {
    super();

    this.state = {
      text: null
    };
  }

  handleTextChange = event => {
    this.setState({
      text: event.target.value
    });
    this.props.onChange(this.state.text);
  };
  focusOther = () => {
    this.props.onFocus(this.props.value);
    this.props.onChange(this.state.text);
  };

  render() {
    return (
      <FormControlLabel
        value={this.props.value}
        control={<Radio />}
        label={
          <TextField
            placeholder="other"
            onChange={this.handleTextChange}
            onFocus={this.focusOther}
          />
        }
        onChange={this.focusOther}
      />
    );
  }
}

Used with:

   <OtherRadioButton
      value="Other"
      onFocus={v => this.setState({ value: v})}
      onChange={v => this.selectItem(v)}
    />

As you can see - the value of the free text is propagating back fine - but the RadioGroup seems like it's not aware of the FormGroupLabel's value.

Why is this, and how would I solve this?

Upvotes: 8

Views: 11881

Answers (1)

Ramil Amparo
Ramil Amparo

Reputation: 632

You can check the RadioGroup source code here. And I have written my own code to better illustrate how it can be fixed. See here: https://codesandbox.io/s/mz1wn4n33j

RadioGroup creates some props to its FormControlLabel/RadioButton children. By creating your own customized radio button in a different component, these props are not passed to FormControlLabel/RadioButton.

You can fix these by passing the props to your FormControlLabel in your custom RadioButton.

<FormControlLabel
    value={this.props.value}       //Pass this
    onChange={this.props.onChange} //Pass this one too
    checked={this.props.checked}   //Also this
    control={<Radio name="gender" />}
    label={
      <TextField
        id="standard-bare"
        defaultValue={this.props.defaultValue}
        margin="normal"
        onChange={this.props.onTextChange}
      />
    }
/>

Upvotes: 7

Related Questions