formik-material-ui not working for TogglleButtonGroup Component
Asked Answered
H

1

9

In my React code, along with other input types, I also have to use ToggleButtonGroup component of material-ui. This component is not directly supported by formik-material-ui and I've been trying to write a custom wrapper without much success. This is how my component looks(formikToggleButtonGroup.tsx):

import * as React from 'react';
import MuiToggleButtonGroup, {
  ToggleButtonGroupProps as MuiToggleButtonGroupProps,
} from '@material-ui/lab/ToggleButtonGroup';
import { FieldProps } from 'formik';

export interface ToggleButtonGroupProps
  extends FieldProps,
    Omit<MuiToggleButtonGroupProps, 'name' | 'value'> {}

export function fieldToToggleButtonGroup({
  field,
  // Exclude Form
  form,
  ...props
}: ToggleButtonGroupProps): MuiToggleButtonGroupProps {
  return {
    ...props,
    ...field,
  };
}

export default function ToggleButtonGroup(props: ToggleButtonGroupProps) {
  return <MuiToggleButtonGroup {...fieldToToggleButtonGroup(props)} />;
}
ToggleButtonGroup.displayName = 'FormikMaterialUIToggleButtonGroup';`

Then, I'm trying to use it like this:

import Layout from '../../components/layout'
import Header from '../../components/header'
import ToggleButtonGroup from '../../components/formikToggleButtonGroup.tsx'
import React, { useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Container from '@material-ui/core/Container';
import CssBaseline from '@material-ui/core/CssBaseline';
import Grid from '@material-ui/core/Grid';
import Box from '@material-ui/core/Box';
import ToggleButton from '@material-ui/lab/ToggleButton';
import { withStyles } from '@material-ui/core/styles';
import { green, orange } from '@material-ui/core/colors';
import Radio from '@material-ui/core/Radio';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import FormControl from '@material-ui/core/FormControl';
import FormLabel from '@material-ui/core/FormLabel';
import * as Yup from "yup";
import { Formik, Form, Field} from 'formik';
import { TextField, RadioGroup } from 'formik-material-ui';
import ToggleButtonGroup from '../../components/formikToggleButtonGroup.tsx'
import ToggleButton from '@material-ui/lab/ToggleButton';

const StyledButton = withStyles((theme)=>({
  root: {
    background: theme.palette.background.paper,
    color: theme.palette.text.primary,
    marginBottom: theme.spacing(3),
    marginRight: theme.spacing(4),
    borderRadius: '0',
    borderWidth: '1px',
    borderColor: theme.palette.divider,
    borderLeft:'1px solid rgba(0, 0, 0, 0.12) !important',
    padding: '0 30px',
    fontSize:'0.7rem',
    fontWeight:'400',
    '&$selected': {
      color: theme.palette.background.default,
      backgroundColor: theme.palette.warning.main,
    },
    '&:hover': {
      color: theme.palette.background.default,
      backgroundColor: theme.palette.warning.light,
    },
    '&$selected:hover': {
      color: theme.palette.background.default,
      backgroundColor: theme.palette.warning.light,
    },
  },
  selected:{
    color: theme.palette.background.default,
    backgroundColor: theme.palette.warning.main,
  },
  hover:{
    color: theme.palette.background.default,
    backgroundColor: theme.palette.warning.light,
  },
  label: {
    textTransform: 'capitalize',
  },
}))(ToggleButton);

export default function GetUserInfo() {
    const classes = useStyles();
    
    const [selectedValue, setSelectedValue] = useState('yes');

    const handleRadioChange = (event) => {
      setSelectedValue(event.target.value);
    };

    const handleSubmit = (evt) => {
        evt.preventDefault();
        alert(`Submitting Name ${name} ${phone} ${email}`)
    }

    const handleChange = (event, newAlignment) => {
      alert(newAlignment)
      if (newAlignment !== null) {
        setGrade(newAlignment);
      }
    };
    
    return (
      <Layout title="My first Next page" meta_desc="Best online coding classes for kids & children">
        <CssBaseline />
        <Header />
        <Container component="main" >
          <Grid container spacing={4}>
            <Grid item xs={12} sm={8} className={classes.boxStyle}>
              <Box mx="auto" p={2}>
                <Formik
                  initialValues={initialValues}
                  validate={
                    values => {
                      const errors = {};
                      if (!values.parentEmail) {
                        errors.parentEmail = 'Required';
                      } else if (
                        !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.parentEmail)
                      ) {
                        errors.parentEmail = 'Invalid email address';
                      } else if (!values.parentName){
                        errors.parentName = 'Required';
                      } else if (!values.countryCode){
                        errors.countryCode = 'Required';
                      } else if (!values.phone){
                        errors.phone = 'Required';
                      } else if (!values.childName){
                        errors.childName = 'Required';
                      } else if (!values.grade){
                        errors.grade = 'Required';
                      } else if (!values.computer){
                        errors.computer = 'Required';
                      }
                      return errors;
                    }
                  }
                  onSubmit={(values, { setSubmitting }) => {
                    setTimeout(() => {
                      setSubmitting(false);
                      alert(JSON.stringify(values, null, 2));
                    }, 500);
                  }}
                >
                  {({ submitForm, isSubmitting }) => (
                    <Form className={classes.root} autoComplete="off">
                        <Box>
                          <Field 
                            component={TextField} 
                            fullWidth 
                            name="childName" 
                            onChange={e => setChildName(e.target.value)} 
                            required id="standard-required" label="Kid's Name"
                            helperText="Certificate will be issued with this name"/>
                        </Box>
                        <Box mt={3} className={classes.labelFont}>
                          Kid's Grade?
                        </Box>
                        <Box mt={2}>
                          <ToggleButtonGroup
                            component={ToggleButtonGroup}
                            mt={7}
                            name="grade"
                            //value={grade}
                            exclusive="true"
                            //onChange={handleChange}
                            aria-label="text alignment"
                          >
                            <StyledButton className={classes.buttonMargin} 
                              value="1" aria-label="left aligned">
                              <label class="btn btn-secondary m-2 rounded">
                                Grade <br/> <strong>1 - 3</strong>
                              </label>
                            </StyledButton>
                            <StyledButton className={classes.buttonMargin} value="2" aria-label="centered">
                              <label class="btn btn-secondary m-2 rounded ">
                                Grade <br/> <strong>4 - 6</strong>
                              </label>
                            </StyledButton>
                            <StyledButton className={classes.buttonMargin} value="3" aria-label="right aligned">
                              <label class="btn btn-secondary m-2 rounded">
                              Grade <br/> <strong>7 - 9</strong>
                              </label>
                            </StyledButton>
                            <StyledButton className={classes.buttonMargin} value="4" aria-label="justified">
                              <label class="btn btn-secondary m-2 rounded">
                              Grade <br/><strong>10 - 12</strong>
                              </label>
                            </StyledButton>
                          </ToggleButtonGroup>
                        </Box>
                        <Button
                        disabled={isSubmitting}
                        onClick={submitForm}
                        //type="submit"
                        //onClick={handleSubmit}
                        fullWidth
                        variant="contained"
                        color="primary"
                        className={classes.submit}>Let's Start
                        </Button>
                      </Form>
                  )}
                  </Formik>
                </Box>
            </Grid>
     
          </Grid>
        </Container>
      </Layout>
    )
  }

The problem I am facing is that value of ToggleButtonGroup is not getting set by Formik. It always shows the initial value.

Hydrothorax answered 10/6, 2020 at 13:55 Comment(0)
F
6

I was able to make formik work with ToggleButtonGroup by manually handling its onChange event, and manually updating the formik instance:

export default function MyComponent() {

  const formik = useFormik({
    initialValues: {
      roleType: 0,
    },
    onSubmit: async (values) => {
       // send ajax request
    },
  });

  // handler for ToggleButtonGroup
  const handleRoleChange = (event: any, role: string) => {
    // manually update formik
    formik.setFieldValue('roleType', role);
  };

  return (
        <form noValidate onSubmit={formik.handleSubmit}>
          <ToggleButtonGroup
            exclusive
            id="roleType"
            value={formik.values.roleType}
            onChange={handleRoleChange}
          >
            <ToggleButton value={0}>
              <PersonIcon />
              <div>Role 1</div>
            </ToggleButton>
            <ToggleButton value={1}>
              <RestaurantIcon />
              <div>Role 2</div>
            </ToggleButton>
          </ToggleButtonGroup>
          <Button type="submit">
            Submit
          </Button>
        </form>
  );
}
Fallon answered 6/5, 2021 at 6:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.