简体   繁体   中英

Radio button with dynamic value from input as label

I am trying to create a radio group component where the value of one of the radio options is dynamically set by an input as a label. I see these often in forms, and have created it without react previously, but am having trouble with react and the material-ui library. The passing of values seems to work from the input to the radio button and therefore to the material-ui radio group component when selected, but it un-focuses (and deselects the radio button if it was selected) after every keystroke so I have to click into the input/label (and re-check the radio button) to continue typing one char at a time.

Code below:

import {FormControl, FormControlLabel, FormLabel, Radio} from "@material-ui/core";
import RadioGroup from "@material-ui/core/RadioGroup/RadioGroup";
import React from "react";
import Input from "@material-ui/core/Input/Input";


const MUIRadioGroup = ({ classes, isSubmitting, label, name, value, onChange, controls }) => {
    return (<FormControl component="fieldset" className={classes.formControl}>
            <FormLabel component="legend">{label}</FormLabel>
            <RadioGroup
                aria-label={label}
                name={name}
                className={classes.group}
                value={value}
                onChange={onChange}
            >
                {controls.map(({ value, disabled, label, ...rest }, i) => {
                  return (<FormControlLabel
                    key={value+i}
                    value={value}
                    disabled={ disabled || isSubmitting }
                    control={ <Radio disabled={ disabled || isSubmitting }/> }
                    label={ label }
                  />)
                })}
            </RadioGroup>
        </FormControl>)
};

class Test extends React.Component {
    state = {
        value: undefined,  // so we don't default select the radio with blank input
        radioInputValue: ''
    }

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

    handleRadioInputChange = (e) => {
        this.setState({ radioInputValue: e.target.value });
    };

    render() {
        const controls=[
                {value: '1', label: 'Choice 1', disabled: false},
                {value: '2', label: 'Choice 2', disabled: false},
                {
                    value: this.state.radioInputValue,
                    label: <Input
                        id={'Ga-radio-input'}
                        key={'Ga-radio-input'}
                        onChange={this.handleRadioInputChange}
                        name={'Ga-radio-input'}
                        value={this.state.radioInputValue}
                    />,
                    disabled: false}
            ];
        return <MUIRadioGroup controls={controls} value={this.state.value} onChange={this.handleChange} isSubmitting={false} label={"Choose one:"}/>
    }
}

I have a feeling this has something to do with rerendering because of stateless child components which would lead me to believe I have to track which components are focused and then pass that down as a prop. Is that the case?

Can someone please provide a simple example of the "React Way" to get this working?

I think you should pass props such as input value and onInputChange function to MUIRadioGroup for your Input component since it is being used as a child component.

This working code is just to give you some idea. I've assumed that you only have one Input for your RadioGroup: https://codesandbox.io/s/1z65z506zl

import {
  FormControl,
  FormControlLabel,
  FormLabel,
  Radio
} from "@material-ui/core";
import RadioGroup from "@material-ui/core/RadioGroup/RadioGroup";
import React from "react";
import ReactDOM from "react-dom";
import Input from "@material-ui/core/Input/Input";

const MUIRadioGroup = ({
  classes,
  isSubmitting,
  label,
  name,
  value,
  onChange,
  controls,
  InputVal,
  onInputChange
}) => {
  return (
    <FormControl component="fieldset">
      <FormLabel component="legend">{label}</FormLabel>
      <RadioGroup
        aria-label={label}
        name={name}
        // className={classes.group}
        value={value}
        onChange={onChange}
      >
        {controls.map(({ value, disabled, label, ...rest }, i) => {
          return (
            <FormControlLabel
              key={value + i}
              value={label ? value : InputVal}
              disabled={disabled || isSubmitting}
              control={<Radio disabled={disabled || isSubmitting} />}
              label={
                label ? (
                  label
                ) : (
                  <Input
                    id={"Ga-radio-input"}
                    key={"Ga-radio-input"}
                    onChange={onInputChange}
                    name={"Ga-radio-input"}
                    value={InputVal}
                  />
                )
              }
            />
          );
        })}
      </RadioGroup>
    </FormControl>
  );
};

class Test extends React.Component {
  state = {
    value: undefined, // so we don't default select the radio with blank input
    radioInputValue: ""
  };

  handleChange = e => {
    this.setState({ value: e.target.value }, () =>
      console.log(this.state.value)
    );
  };

  handleRadioInputChange = e => {
    this.setState({ radioInputValue: e.target.value }, () => {
      console.log(this.state.radioInputValue);
    });
  };

  render() {
    const controls = [
      { value: "1", label: "Choice 1", disabled: false },
      { value: "2", label: "Choice 2", disabled: false },
      {
        value: "",
        label: null,
        disabled: false
      }
    ];
    return (
      <MUIRadioGroup
        controls={controls}
        value={this.state.value}
        onChange={this.handleChange}
        isSubmitting={false}
        label={"Choose one:"}
        InputVal={this.state.radioInputValue}
        onInputChange={this.handleRadioInputChange}
      />
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Test />, rootElement);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM