0
votes

I have Formik FieldArray integration in my React Web app as below, but I am not getting values of input field when I enter value in textfield, handleChange event is not working I think. How can I get input values in below case.

From WrapperForm also I am calling different sub form or children. I am not sure how to pass props to children.

 return (
  <div className={classes.container}>
    <Formik
      initialValues={{
        profile: [
          {
            id: Math.random(),
            firstName: "Test",
            lastName: "",
            email: ""
          }
        ]
      }}
      validationSchema={validationSchema}
      onSubmit={values => {
        console.log("onSubmit", JSON.stringify(values, null, 2));
      }}
    >
      {({ values, touched, errors, handleChange, handleBlur, isValid }) => (
        <Form noValidate autoComplete="off">
          <FieldArray name="profile">
            {({ push, remove }) => (
              <div>
                {values.profile.map((p, index) => {

                  return (
                    <div key={p.id}>
                        <Grid container spacing={3} >
                            <Grid item xs={12} sm={6}>
                                <WrapperForm index = {index} remove={remove} touched={touched} errors={errors} handleChangeOnText={handleChange} handleBlur={handleBlur} /> 
                            </Grid>
                        </Grid>
                    </div>
                  );
                })}
                <Button
                  className={classes.button}
                  variant="contained"
                  color="primary"
                  startIcon={<AddCircleIcon />}
                  onClick={() =>
                    push({ id: Math.random(), firstName: "", lastName: "" })
                  }
                >
                  Add More
                </Button>
              </div>
            )}
          </FieldArray>
          <Divider style={{ marginTop: 20, marginBottom: 20 }} />
          <Button
            className={classes.button}
            type="submit"
            color="primary"
            variant="contained"
            // disabled={!isValid || values.people.length === 0}
          >
            submit
          </Button>
          <Divider style={{ marginTop: 20, marginBottom: 20 }} />
          {debug && (
            <>
              <pre style={{ textAlign: "left" }}>
                <strong>Values</strong>
                <br />
                {JSON.stringify(values, null, 2)}
              </pre>
              <pre style={{ textAlign: "left" }}>
                <strong>Errors</strong>
                <br />
                {JSON.stringify(errors, null, 2)}
              </pre>
            </>
          )}
        </Form>
      )}
    </Formik>

WrapperForm.js

export default function HorizontalLinearStepper({index, remove, touched, errors, handleChangeOnText, handleBlur}) {

....
....

function getStepContent(step, index, touched, errors, handleChangeOnText, handleBlur) {
  switch (step) {
   case 0:
    return <Profile index={index} touched={touched} errors={errors} handleChangeOnText=. {handleChangeOnText} handleBlur={handleBlur} />;
   case 1:
    return <Offer index={index} touched={touched} errors={errors} handleChangeOnText=. {handleChangeOnText} handleBlur={handleBlur} />;
  case 2:
   return 'This is the bit I really care about!';
  default:
  return 'Unknown step';
 }
}
return (
<div className={classes.layout}>
    <Paper variant="outlined" className={classes.paper}>
        <Grid container spacing={3}>
            <Grid item xs={12} sm={6}>
                <TextField
                    required
                    id="email"
                    //name={`${member}.email`}
                    label="Email"
                    fullWidth
                    autoComplete="email"
                />
            </Grid>
            <Grid item xs={12} sm={4}>
                <InputLabel htmlFor="brand-native-simple">Brand</InputLabel>
                <Select
                    native
                    value={state.brand}
                    onChange={handleChange}
                    inputProps={{
                        name: 'brand',
                        id: 'brand-native-simple',
                    }}
                >
                    <option aria-label="None" value="" />
                    <option value={'gp'}>GAP</option>
                    <option value={'br'}>BANANA REP</option>
                    <option value={'on'}>OLDNAVY</option>
                </Select>
            </Grid>
        </Grid>
            <Stepper activeStep={activeStep} className={classes.stepper} >
            {steps.map((label, index) => {
            const stepProps = {};
            const labelProps = {};
            if (isStepOptional(index)) {
                labelProps.optional = <Typography variant="caption">Optional</Typography>;
            }
            if (isStepSkipped(index)) {
                stepProps.completed = false;
            }
            return (
                <Step key={label} {...stepProps}>
                <StepLabel {...labelProps}>{label}</StepLabel>
                </Step>
            );
            })}
        </Stepper>
        <div>
            {activeStep === steps.length ? (
            <div>
                <Typography className={classes.instructions}>
                All steps completed - you&apos;re finished
                </Typography>
                <Button onClick={handleReset} className={classes.button}>
                Reset
                </Button>
            </div>
            ) : (
            <div>
                {getStepContent(activeStep, index, touched, errors, handleChangeOnText, handleBlur)} 

                <div>
                <Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
                    Back
                </Button>
                {isStepOptional(activeStep) && (
                    <Button
                    variant="contained"
                    color="primary"
                    onClick={handleSkip}
                    className={classes.button}
                    >
                    Skip
                    </Button>
                )}

                <Button
                    variant="contained"
                    color="primary"
                    onClick={handleNext}
                    className={classes.button}
                >
                    {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
                </Button>
                <Button
                    variant="contained"
                    color="secondary"
                    className={classes.button}
                    startIcon={<DeleteIcon />}
                    onClick={() => remove(index)}
                >
                    Remove
                </Button>
                </div>
            </div>
            )}
1

1 Answers

0
votes

I see some problems with your code here, first thing is you have to pass formik values as props to WrapperForm,

<WrapperForm values={values} {...otherPropsYouArePassing} /> 

Next you need to iterate over these values in the WrapperForm:

<div>
  {
    // You are getting these values from props in WrapperForm
    values.profile && 
    values.profile.length > 0 &&
    values.profile.map((x, idx) => {
      // Return you JSX here
      return (...);
    })

  }
</div>

And lastly you need to name your inputs right like these:

// I'm assuming your data structure to be like this
/*
{
  profile: [{ email: '', ... }, ...]
}
*/
<TextField
  required
  id="email"
  name={`profile[${idx}].email`} // We're getting idx from the map above
  label="Email"
  fullWidth
  autoComplete="email"
/>