skip to Main Content

I am trying to implement React Material UI Autocomplete component by using Formik (setFormValue) and custom renderOption property, so I don’t use TextField component, but custom input field.

Filtering options works as expected, so when I enter some value in custom input, the results are displayed depending on what I typed in, but I have an issue with selecting an option. When I click when I click one of the offered ones, nothing happens.

I created FilterDropdown component so it can be reusable. Please see my code and tell me where I wrong.

I did debugging through Google chrome breakpoints, and when I click on any available dropdown option, nothing happens.

filter-dropdown/index.tsx

import { createElement } from 'react'
import { Divider } from '@eframe-ui/react'
import { FilterDropdownProps, DropdownOptionProps } from './types'
import { Translate } from '../translate'
import { Autocomplete } from '@mui/material'
import { FilterDropdownInput } from './Input'

export const FilterDropdown = ({
  data,
  dropdownDataLayout,
  selectFieldLabel,
  fieldValue,
  errors,
  setFieldValue,
}: FilterDropdownProps) => {
  return (
    <Autocomplete
      freeSolo
      className="gap-y-1 flex flex-col"
      options={data}
      getOptionLabel={(option: string | DropdownOptionProps) =>
        (option as { value: string }).value
      } // filter value
      onChange={(e, value) => setFieldValue(fieldValue, value)}
      renderInput={(params) => (
        <FilterDropdownInput
          error={errors}
          params={params}
          label={selectFieldLabel}
        />
      )}
      renderOption={(props, option: DropdownOptionProps) => {
        const { label, mixin } = option

        return dropdownDataLayout
          ? createElement(dropdownDataLayout, mixin as Record<string, string>)
          : label && (
              <div className="flex flex-col w-full">
                <Translate label={label} />
                <Divider className="!my-2" />
              </div>
            )
      }}
    />
  )
}

Input.tsx

import { TextField } from '@/../ui'
import { useTranslation } from 'react-i18next'
import { AutocompleteRenderInputParams } from '@mui/material'

interface FilterDropdownProps {
  params: AutocompleteRenderInputParams
  label: string
  error: string | JSX.Element | undefined
}

export const FilterDropdownInput = ({
  params,
  label,
  error,
}: FilterDropdownProps) => {
  const { t } = useTranslation()

  return (
    <div ref={params.InputProps.ref}>
      <TextField
        {...params.inputProps}
        label={t(label)}
        placeholder={t('common:Field.Search', 'Enter search term')}
        error={!!error}
        helperText={error}
      />
    </div>
  )
}

transfer-assets.tsx

  const TransferAssetsLayout = (option: Record<string, string>) => (
    <div
      className="funds flex flex-col w-full cursor-pointer"
      onClick={() => setFieldValue('pension_fund_name', option.name)}
    >
      <p className="text-text-primary typo-regular-300 px-2">{option.name}</p>
      {option.recipient && (
        <p
          className={clsx(
            classes.italic,
            'text-text-secondary typo-regular-200 px-2 pb-1',
          )}
        >
          {option.recipient}
        </p>
      )}
      <p
        className={clsx(
          classes.italic,
          'text-text-secondary typo-regular-200 px-2 pb-1',
        )}
      >
        {`${option.address}, ${option.zip_code} ${option.location}`}
      </p>
      <Divider className="!m-0" />
    </div>
  )

    <FilterDropdown
      data={pensionFundsData}
      dropdownDataLayout={TransferAssetsLayout}
      selectFieldLabel="USM-PortfolioEdit:TransferAssets.InstitutionName"
      fieldValue={'pension_fund_name'}
      buttonLabel={pension_fund_name}
      setFieldValue={() => setFieldValue}
      errors={errors.pension_fund_name}
    />

2

Answers


  1. Chosen as BEST ANSWER

    I fixed the issue , this is my solution

    import { createElement, HTMLAttributes } from 'react'
    import { Divider } from '@eframe-ui/react'
    import { FilterDropdownProps, DropdownOptionProps } from './types'
    import { Translate } from '../translate'
    import { Autocomplete, Paper } from '@mui/material'
    import { FilterDropdownInput } from './Input'
    
    export const FilterDropdown = ({
      data,
      dropdownDataLayout,
      selectFieldLabel,
      fieldValue,
      errors,
      setFieldValue,
    }: FilterDropdownProps) => {
      /* eslint-disable @typescript-eslint/no-explicit-any */
      const CustomPaper = (props: any) => (
        <Paper {...props} sx={{ background: '#f4f7fa', marginTop: '4px' }} />
      )
    
      return (
        <Autocomplete
          freeSolo
          className="gap-y-1 flex flex-col"
          options={data}
          getOptionLabel={(option: string | DropdownOptionProps) =>
            (option as { value: string }).value
          } // filter value
          onChange={(e, value) => setFieldValue(fieldValue, value)}
          renderInput={(params) => (
            <FilterDropdownInput
              {...params}
              error={errors}
              params={params}
              label={selectFieldLabel}
            />
          )}
          renderOption={(
            props: HTMLAttributes<HTMLLIElement>,
            option: DropdownOptionProps,
          ) => {
            const { label, mixin } = option
    
            return (
              <>
                <li {...props} className="w-full cursor-pointer">
                  {dropdownDataLayout
                    ? createElement(
                        dropdownDataLayout,
                        mixin as Record<string, string>,
                      )
                    : label && (
                        <>
                          <Translate label={label} />
                          <Divider className="!my-2" />
                        </>
                      )}
                </li>
              </>
            )
          }}
          PaperComponent={CustomPaper}
        />
      )
    }
    

  2. You need to apply the MUI input props or Autocomplete loses track of your custom input.

    Instead of this:

    renderInput={(params) => (
      <FilterDropdownInput
        error={errors}
        params={params}
        label={selectFieldLabel}
      />
    )}
    

    Use this:

    renderInput={(params) => (
      <FilterDropdownInput
        {...params}
        error={errors}
        params={params}
        label={selectFieldLabel}
      />
    )}
    

    Example working sandbox of MUI Autocomplete passing props down to through renderInput. You must use {...params} exactly as can be verified.

    <Autocomplete
      options={someData.sort((a, b) => a.value - b.value)}
      getOptionLabel={(option) => option.label}
      value={value}
      onChange={handleChange}
      disabled={(someData || []).length >= 5}
      renderInput={(params) => (
        <TextField
          {...params}
          size="small"
          label="Type some stuff"
          variant="outlined"
        />
      )}
    />
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search