Search code examples
reactjsradio-groupreact-propsreact-final-form

Adding custom prop to RadioGroup field with React Final Form


I am making a RadioGroup and as I understand it the value has to be a string but I want a number so I can do some math with other component inputs.

Would rather just have a custom prob like carPrice below but failing that some other way is fine. Any ideas please? this is driving me crazy now. Not found anything in the docs for ReactJS or Final Form about doing it or anywhere else I have looked.

The commented lines are just some things I have tried as examples but there has been many more.

I know how to do this with jQuery but I really wanted to get into React more. Especially Final Form.

Of course, the most obvious thing would be to use the value with a number integer/float but that throws the error related to the protected 'type' having to be a string.

Do I need to go as far as making a handler and what kind? Surely there is a way to just add it as a custom prop to the field?

I could do this with jQuery but I really wanted to stick to ReactJS and Final form.

Been trying to work this out for so long I am going code blind to solutions.

<RadioGroup row>
  <FormControlLabel
    label="Ford"
    control={
      <Field
        name="Ford"
        component={Radio}
        type="radio"
        defaultValue={0}
        value={11}
        //onClick={e => alert(e.target.value)}
        //carPrice={555}
        // value={`${55}`}
        // value={888 ? String(yourValue) : null}
        // props = {{ myPrice: 475 }}

      />
    }
  />

Solution

  • If I understand the requirements correctly:

    • you want a RadioGroup, with different car types
    • each car has a price value associated with it
    • you want to use the car price stored in your form for other calculations

    I think the root of the problem is that the Radio component requires props with a different shape, not in the shape react-final-form is injecting them. react-final-from props look like this (more info about FieldRenderProps here):

    const { input, meta } = props;
    const { name, onChange, value } = input;
    

    You would need to write a wrapper component around Radio to convert the props to the required shape. Are you using material-ui? There is already a library that will do that for you: final-form-material-ui

    A set of wrapper components to facilitate using Material-UI with Final Form.


    UPDATE: The code snippet below does not work correctly. Scroll past it to the updated answer.

    So this is how the code would look like:

    import { FormControlLabel, RadioGroup } from '@material-ui/core';
    import { Radio } from 'final-form-material-ui';
    import { Field } from 'react-final-form';
    
    // ...
    
        <RadioGroup row>
            <FormControlLabel
              label="Ford"
              control={<Field name="carPrice" component={Radio} type="radio" value={475} />}
            />
            <FormControlLabel
              label="Mercedes"
              control={<Field name="carPrice" component={Radio} type="radio" value={555} />}
            />
        </RadioGroup>
    

    There seems to be an issue with the checked state of the radio button when its value is a number, and not a string. As you can see in this codesandbox example the form value changes, but the radio buttons do not reflect this.


    UPDATED SOLUTION:

    You can store the whole car object (brand and price) in the form state.

    <Form
      initialValues={{ car: { brand: 'Ford', price: 475 } }}
      // ...
    

    And use the format and parse FieldProps functions to achieve a working checked state and having the correct form state value.

    <FormControlLabel
      label={"Ford"}
      control={
        <Field
          name="car"
          format={car => car.brand}
          parse={() => ({ brand: "Ford", price: 475 })}
          component={Radio}
          type="radio"
          value={"Ford"}
        />
      }
    />
    

    Here's the working codesandbox example.