How do I autofill the other autocomplete values based on the selected data and also add the data if it does not exist yet?

Viewed 88

How can I match the first and last name and then have it autofill the other Autocomplete fields as well? There might be situations where there are multiple similar first names or last names but the addresses are different. Also, add the first name, last name, and address if it does not exist in the data.

So far, I was not able to match the first and last names. However, if the user does not exist, I can add and see their first name, last name, and address in the console.

Recreated codesandbox: https://codesandbox.io/s/freesolocreateoption-demo-material-ui-forked-oclo3s?file=/demo.js

Codes:

export default function FreeSoloCreateOption() {
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [streetAddress, setStreetAddress] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(firstName, "firstName");
    console.log(lastName, "firstName");
    console.log(streetAddress, "street address");
  };
  return (
    <form onSubmit={handleSubmit}>
      <Autocomplete
        required
        value={firstName}
        onChange={(event, newValue) => {
          if (typeof newValue === "string") {
            setFirstName(newValue);
          } else if (newValue && newValue.inputValue) {
            // Create a new value from the user input
            setFirstName(newValue.inputValue);
          } else {
            setFirstName(newValue);
          }
        }}
        filterOptions={(options, params) => {
          const filtered = filter(options, params);

          const { inputValue } = params;
          // Suggest the creation of a new value
          const isExisting = options.some(
            (option) => inputValue === option.firstName
          );
          if (inputValue !== "" && !isExisting) {
            filtered.push({
              inputValue,
              firstName: `Add "${inputValue}"`
            });
          }

          return filtered;
        }}
        selectOnFocus
        clearOnBlur
        handleHomeEndKeys
        id="free-solo-with-text-demo"
        options={data}
        getOptionLabel={(option) => {
          // Value selected with enter, right from the input
          if (typeof option === "string") {
            return option;
          }
          // Add "xxx" option created dynamically
          if (option.inputValue) {
            return option.inputValue;
          }
          // Regular option
          return option.firstName;
        }}
        renderOption={(props, option) => <li {...props}>{option.firstName}</li>}
        sx={{ width: 300 }}
        freeSolo
        renderInput={(params) => <TextField {...params} label="First Name" />}
      />
      <br />

      <Autocomplete
        value={lastName}
        onChange={(event, newValue) => {
          if (typeof newValue === "string") {
            setLastName(newValue);
          } else if (newValue && newValue.inputValue) {
            // Create a new value from the user input
            setLastName(newValue.inputValue);
          } else {
            setLastName(newValue);
          }
        }}
        filterOptions={(options, params) => {
          const filtered = filter(options, params);

          const { inputValue } = params;
          // Suggest the creation of a new value
          const isExisting = options.some(
            (option) => inputValue === option.lastName
          );
          if (inputValue !== "" && !isExisting) {
            filtered.push({
              inputValue,
              lastName: `Add "${inputValue}"`
            });
          }

          return filtered;
        }}
        selectOnFocus
        clearOnBlur
        handleHomeEndKeys
        id="free-solo-with-text-demo"
        options={data}
        getOptionLabel={(option) => {
          // Value selected with enter, right from the input
          if (typeof option === "string") {
            return option;
          }
          // Add "xxx" option created dynamically
          if (option.inputValue) {
            return option.inputValue;
          }
          // Regular option
          return option.lastName;
        }}
        renderOption={(props, option) => <li {...props}>{option.lastName}</li>}
        sx={{ width: 300 }}
        freeSolo
        renderInput={(params) => <TextField {...params} label="Last Name" />}
        required
      />

      <br />
      <Autocomplete
        value={streetAddress}
        onChange={(event, newValue) => {
          if (typeof newValue === "string") {
            setStreetAddress(newValue);
          } else if (newValue && newValue.inputValue) {
            // Create a new value from the user input
            setStreetAddress(newValue.inputValue);
          } else {
            setStreetAddress(newValue);
          }
        }}
        filterOptions={(options, params) => {
          const filtered = filter(options, params);

          const { inputValue } = params;
          // Suggest the creation of a new value
          const isExisting = options.some(
            (option) => inputValue === option.streetAddress
          );
          if (inputValue !== "" && !isExisting) {
            filtered.push({
              inputValue,
              streetAddress: `Add "${inputValue}"`
            });
          }

          return filtered;
        }}
        selectOnFocus
        clearOnBlur
        handleHomeEndKeys
        id="free-solo-with-text-demo"
        options={data}
        getOptionLabel={(option) => {
          // Value selected with enter, right from the input
          if (typeof option === "string") {
            return option;
          }
          // Add "xxx" option created dynamically
          if (option.inputValue) {
            return option.inputValue;
          }
          // Regular option
          return option.streetAddress;
        }}
        renderOption={(props, option) => (
          <li {...props}>{option.streetAddress}</li>
        )}
        sx={{ width: 300 }}
        freeSolo
        renderInput={(params) => (
          <TextField {...params} label="Street Address" />
        )}
        required
      />
      <Button type="submit">submit</Button>
    </form>
  );
}

// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
const data = [
  {
    streetAddress: "Street Address 1",
    firstName: "Alex",
    lastName: "Dhan"
  },
  {
    streetAddress: "Street Address 2",
    firstName: "Alex",
    lastName: "Dhan"
  },
  {
    streetAddress: "Street Address 3",
    firstName: "Alex",
    lastName: "Last name"
  },
  {
    streetAddress: "Street Address 4",
    firstName: "Jin",
    lastName: "Iu"
  },
  {
    streetAddress: "Street Address 5",
    firstName: "Po",
    lastName: "Yie"
  }
];
 
2 Answers

You need a helper to filter options based on what you defined for your options (firstName, lastName and streetAddress). it could be something like:

function filterData(allData, { firstName, lastName }) {
  const filteredData = allData.filter((dt) => {
    const first =
      typeof firstName === "string" ? firstName : firstName?.firstName;
    const last = typeof lastName === "string" ? lastName : lastName?.lastName;

    return (
      (!first || first === dt.firstName) && (!last || last === dt.lastName)
    );
  });

  // TODO: This line enables you to select from list data if nothing left!
  // Remove it and just return filteredData if you want filter works normally :)
  return filteredData.length ? filteredData : allData;
}

This helps you to:

  1. Filter options,
  2. And, set the value of

next autocompletes based on what you currently selected.

Take a look at this code on Codesandbox to see how it works.

Follow TODO tags in code to get more data about available options.

If I get it right you want to add new data to autoComplete, Mui example doesn't show added value to the options array. you have to save data in option array by using local state or API:

import * as React from 'react'
import Autocomplete, { createFilterOptions } from '@mui/material/Autocomplete'
import { TextField } from '../TextField/TextField'

const filter = createFilterOptions<string>()

const trimCreatedValue = (addedValue: string | null) => {
  if (typeof addedValue !== 'string') return ''

  // extract actual word between " e.g. added option "
  const _o = addedValue.match(/"(.*?)"/)

  // Add "xxx" option created dynamically
  if (_o) {
    return _o[1]
  }
  return addedValue
}

export const SelectCreate: React.FC<IPropsSelectCreate> = ({ items, onChange }) => {
  const [value, setValue] = React.useState<string | null>(null)

  return (
    <Autocomplete
      value={value}
      onChange={(_event, newValue: string | null) => {
        setValue(trimCreatedValue(newValue))
        onChange(trimCreatedValue(newValue))
      }}
      filterOptions={(options: string[], params) => {
        const filtered = filter(options, params)

        const { inputValue } = params
        // Suggest the creation of a new value
        const isExisting = options.some(option => inputValue === option)
        if (inputValue !== '' && !isExisting) {
          filtered.push(`Add "${inputValue}"`)
        }

        return filtered
      }}
      options={items}
      getOptionLabel={trimCreatedValue}
      renderOption={(props, option) => <li {...props}>{option}</li>}
      freeSolo
      renderInput={params => <TextField {...params} />}
    />
  )
}

export interface IPropsSelectCreate {
  items: string[]
  onChange: (val: string | null) => void
}

Related