Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disable the selection of an item when the first letter of the option is pressed in the Select component?

I'm using material UI Select component and I'm trying to build a filter inside to display only the items that match the input entered by the user.

I build a minimal example of what I'm developing.

function App() {
  const [selectedOption, setSelectedOption] = React.useState("");
  const [filterExpression, setFilterExpression] = React.useState("");

  const onChangeSelection = (
    event: React.ChangeEvent<{ name?: string | undefined; value: unknown }>,
    child: React.ReactNode
  ) => {
    const value = event.target.value.toString();
    setSelectedOption(value);
  };

  const onChangeExpression = (
    event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
  ) => {
    const value = event.target.value.toString();
    console.log(`value:`, value);
    setFilterExpression(value);
  };

  const stopImmediatePropagation = (e: any) => {
    e.stopPropagation();
    e.preventDefault();
  };

  return (
    <div className="App">
      <Select onChange={onChangeSelection} value={selectedOption}>
        <MenuItem
          dense
          divider
          value={""}
          onClickCapture={stopImmediatePropagation}
        >
          <TextField value={filterExpression} onChange={onChangeExpression} />
        </MenuItem>

        <MenuItem dense key={"One"} value={"One"}>
          One
        </MenuItem>
        <MenuItem dense key={"Two"} value={"Two"}>
          Two
        </MenuItem>
        <MenuItem dense key={"Three"} value={"Three"}>
          Three
        </MenuItem>
      </Select>
    </div>
  );
}

My problem now is that by default the select component allows the user to press any letter and if there is an option in which the first letter matches the user input, it selects that option.

So, if I have 3 options (One, Two and Three) and the user types O the select component will select the One option and the value of my text field won't change. However, if the user types F the text field will be updated to F.

I would like to disable this behavior, so, I have been trying to stop the propagation of events like onKeyUpCapture, onChangeCapture, onKeyDownCapture but I haven't' been able to avoid this.

Do you have any suggestions to fix it? You can check the functional example here:

Edit inspiring-ramanujan-sv25c

like image 926
fingerprints Avatar asked Oct 14 '19 14:10

fingerprints


1 Answers

The text focus navigation functionality is implemented in the onKeyDown of MenuList (I implemented it about 6 months ago). Stopping propagation of that event on the MenuItem (it would also work to stop propagation on the TextField) prevents the event from reaching MenuList.

import * as React from "react";
import { render } from "react-dom";
import TextField from "@material-ui/core/TextField";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";

import "./styles.css";

function App() {
  const [selectedOption, setSelectedOption] = React.useState("");
  const [filterExpression, setFilterExpression] = React.useState("");

  const onChangeSelection = (
    event: React.ChangeEvent<{ name?: string | undefined; value: unknown }>,
    child: React.ReactNode
  ) => {
    const value = event.target.value.toString();
    setSelectedOption(value);
  };

  const onChangeExpression = (
    event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
  ) => {
    const value = event.target.value.toString();
    console.log(`value:`, value);
    setFilterExpression(value);
  };

  const stopImmediatePropagation = (e: any) => {
    e.stopPropagation();
    e.preventDefault();
  };

  return (
    <div className="App">
      <Select onChange={onChangeSelection} value={selectedOption}>
        <MenuItem
          dense
          divider
          value={""}
          onClickCapture={stopImmediatePropagation}
          onKeyDown={e => e.stopPropagation()}
        >
          <TextField value={filterExpression} onChange={onChangeExpression} />
        </MenuItem>

        <MenuItem dense key={"One"} value={"One"}>
          One
        </MenuItem>
        <MenuItem dense key={"Two"} value={"Two"}>
          Two
        </MenuItem>
        <MenuItem dense key={"Three"} value={"Three"}>
          Three
        </MenuItem>
      </Select>
    </div>
  );
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);

Edit Stop text focus navigation

like image 194
Ryan Cogswell Avatar answered Nov 02 '22 11:11

Ryan Cogswell