6

I want use Formik's form validation and it actually works just fine, but I ran into some issues with selected value display in Autocomplete component. I Have created Add/Remove buttons to dynamically adjust how many rows are in my form. The bug occurs when I try to remove form row, the row below, behind scenes has proper values as displayed in DEBUG, but user's input displays value from deleted form row. I cannot figure out, how to display or handle this occurrence. Form before removal, Form after removal

<FieldArray name="actions"
        render={arrayHelpers =>
            values.actions.map((action, index) => (
                <Grid item container spacing={1} justify="center" alignItems="center"
                        key={index}>
                    <Grid item xs={4}>
                        <Field
                            error={getIn(errors, `actions.${index}.suggestedAction`) &&
                            getIn(touched, `actions.${index}.suggestedAction`)}
                            helperText={<ErrorMessage
                                name={`actions.${index}.suggestedAction`}/>}
                            name={`actions.${index}.suggestedAction`}
                            id={`actions.${index}.suggestedAction`}
                            variant="outlined"
                            fullWidth
                            as={TextField}
                            label="Siūloma priemonė"
                            multiline
                            rows={3}
                            rowsMax={10}
                        />
                    </Grid>
                    <Grid item xs={4}>
                        <Autocomplete
                            freeSolo
                            onBlur={handleBlur}
                            onChange={(e, value) => {
                                //If adding new
                                if (value && value.inputValue) {
                                    setOpen(true);
                                    setFieldValue(`actions.${index}.responsiblePerson`, value.inputValue)
                                } else if (value && value.id) {
                                    //Selecting existing
                                    setFieldValue(`actions.${index}.responsiblePerson`, value.id)
                                } else {
                                    setFieldValue(`actions.${index}.responsiblePerson`, "")
                                }
                            }}
                            getOptionLabel={(option) => {
                                if (typeof option === 'string') {
                                    return option;
                                }
                                if (option.inputValue) {
                                    return option.inputValue;
                                }
                                return option.title;
                            }}
                            handleHomeEndKeys
                            clearText="Pašalinti"
                            noOptionsText="Tuščia..."
                            renderOption={option => option.title}
                            filterOptions={(options, params) => {
                                const filtered = filter(options, params);
                                if (params.inputValue !== '') {
                                    filtered.push({
                                        inputValue: params.inputValue,
                                        title: `Pridėti "${params.inputValue}"`,
                                    });
                                }
                                return filtered;
                            }}
                            renderInput={params => (
                                <TextField
                                    {...params}
                                    id={`actions.${index}.responsiblePerson`}
                                    name={`actions.${index}.responsiblePerson`}
                                    error={getIn(errors, `actions.${index}.responsiblePerson`) &&
                                    getIn(touched, `actions.${index}.responsiblePerson`)}
                                    helperText={<ErrorMessage
                                        name={`actions.${index}.responsiblePerson`}/>}
                                    onChange={handleChange}
                                    variant="outlined"
                                    label="Atsakingas asmuo"
                                    placeholder="Vardenis Pavardenis"
                                />
                            )}
                            options={top100Films}/>
                    </Grid>
                    <DateTimeUtilsProvider>
                        <Grid item xs={3}>
                            <Field
                                disableToolbar
                                as={KeyboardDatePicker}
                                variant="inline"
                                inputVariant="outlined"
                                format="yyyy-MM-dd"
                                id={`actions.${index}.deadline`}
                                name={`actions.${index}.deadline`}
                                error={getIn(errors, `actions.${index}.deadline`) &&
                                getIn(touched, `actions.${index}.deadline`)}
                                helperText={<ErrorMessage
                                    name={`actions.${index}.deadline`}/>}
                                label="Įvykdymo terminas"
                                onChange={value =>
                                    setFieldValue(`actions.${index}.deadline`, value)}
                            />
                        </Grid>
                    </DateTimeUtilsProvider>
                    <Grid item xs={1}>
                        <ButtonGroup fullWidth orientation="vertical" size="medium">
                            <Button onClick={() => {
                                arrayHelpers.remove(index);
                            }}
                                    disabled={values.actions.length === 1}
                                    classes={removeButtonClasses}>
                                <HighlightOff/>
                            </Button>
                            <Button onClick={() => {
                                arrayHelpers.insert(index + 1, {
                                    suggestedAction: "",
                                    responsiblePerson: "",
                                    deadline: Date.now()
                                })
                            }}
                                    color="primary">
                                <AddCircleOutline/>
                            </Button>
                        </ButtonGroup>
                    </Grid>
                </Grid>
            ))
        }
/>
</Grid>
Benjamin Charais
  • 1,248
  • 8
  • 17
Edward
  • 93
  • 3

3 Answers3

0

Instead of

arrayHelpers.insert()

I have used

arrayHelpers.push()

and its working fine for me.

0

I had this same problem. I was setting a value prop on the <Field> inside my renderInput.

<Autocomplete
  renderInput={params => (
    <Field {...params} component={TextField} value={values.myArray[index]} />
  )}
/>

I was able to fix it by moving the value attribute to the Autocomplete.

<Autocomplete
  value={values.myArray[index]}
  renderInput={params => (
    <Field {...params} component={TextField} />
  )}
  ...
/>
Michael Lynch
  • 2,682
  • 3
  • 31
  • 59
0

This worked for me

const arrayValue = options.filter(
(item) => item.id === values[arrayName][index][name]);

And then I used the filtered option as my value in the Autocomplete component

<Autocomplete
    name={name}
    value={arrayValue.length > 0 ? arrayValue[0] : null}
    options={options}
    groupBy={(option) => option.group}
    getOptionLabel={(option) => option.value}
    isOptionEqualToValue={(option, value) => option?.id === value?.id}
    defaultValue={defaultValueCheck()}
    onChange={(_, value) => {
      setFieldValue(`${arrayName}[${index}].${name}`, value?.id ?? "");
    }}
    renderInput={(params) => (
      <TextField
        {...params}
        {...configTextField}
        name={`${arrayName}[${index}].${name}`}
      />
    )}
    renderGroup={(params) => (
      <li key={params.key}>
        <GroupHeader>{params.group}</GroupHeader>
        <GroupItems>{params.children}</GroupItems>
      </li>
    )}
  />
</>
Mike
  • 1
  • 1