【问题标题】:Material ui Autocomplete: can tags be created on events aside from 'Enter' events?Material ui Autocomplete:除了“Enter”事件之外,是否可以在事件上创建标签?
【发布时间】:2020-03-20 23:28:47
【问题描述】:

我目前正在使用 freesolo 自动完成功能,我的特定用例要求在输入文本后面有逗号或空格时创建标签。 Autocomplete 目前在 Enter 事件上创建标签,但我认为 Autocomplete 中还没有内置任何东西支持在任何其他事件上创建标签。我想知道我是否缺少任何东西,或者如果我没有,我该如何解决这个问题?

目前,我正在尝试使用 Autocomplete 中的 onInputChange 属性来捕获传入的字符串。我检查该字符串的逗号和空格,并在成功找到其中一个字符后,我使用手动触发 Enter 事件一些原生 JS 代码。这在某些情况下有效,但并非在所有情况下都适用,并且考虑所有情况变得乏味。这种方法似乎容易出现很多问题,我不相信这是在不同事件上实现标签创建的最佳方法。寻找一些想法。谢谢

onInputChange属性用法:

<Autocomplete
        multiple
        freeSolo
        filterSelectedOptions
        id="auto-complete"
        options={foo.map(bar => bar.name)}
        ref={autoRef}
        onInputChange={(e, value) => {
            createTagOnEvent(value);
        }}/>

在输入中搜索逗号和空格并手动触发 Enter 事件:

const createTagOnEvent = (bar) => {
    if (pattern.test(bar)) {
        const ke = new KeyboardEvent("keydown", {bubbles: true, cancelable: true, keyCode: 13});
        autoRef.current.dispatchEvent(ke);
    }
};

【问题讨论】:

    标签: javascript reactjs material-ui


    【解决方案1】:

    以下是我推荐的方法。

    该方法有两个主要方面:

    1. Autocomplete 使用"controlled" input 方法,以便您完全控制当前值。

    2. 为通过params.inputProps.onKeyDown 输入的TextField 指定onKeyDown 处理程序,并使用适当的逻辑来添加新值。

    import React from "react";
    import TextField from "@material-ui/core/TextField";
    import Autocomplete from "@material-ui/lab/Autocomplete";
    
    export default function Tags() {
      const [value, setValue] = React.useState([top100Films[13]]);
      const handleKeyDown = event => {
        switch (event.key) {
          case ",":
          case " ": {
            event.preventDefault();
            event.stopPropagation();
            if (event.target.value.length > 0) {
              setValue([...value, event.target.value]);
            }
            break;
          }
          default:
        }
      };
      return (
        <div style={{ width: 500 }}>
          <Autocomplete
            multiple
            freeSolo
            id="tags-outlined"
            options={top100Films}
            getOptionLabel={option => option.title || option}
            value={value}
            onChange={(event, newValue) => setValue(newValue)}
            filterSelectedOptions
            renderInput={params => {
              params.inputProps.onKeyDown = handleKeyDown;
              return (
                <TextField
                  {...params}
                  variant="outlined"
                  label="filterSelectedOptions"
                  placeholder="Favorites"
                  margin="normal"
                  fullWidth
                />
              );
            }}
          />
        </div>
      );
    }
    
    // Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
    const top100Films = [
      { title: "The Shawshank Redemption", year: 1994 },
      { title: "The Godfather", year: 1972 },
    // ... many more options
    ];
    

    这是一个 Typescript 版本:

    /* eslint-disable no-use-before-define */
    import React from "react";
    import TextField from "@material-ui/core/TextField";
    import Autocomplete, { RenderInputParams } from "@material-ui/lab/Autocomplete";
    
    interface ObjectOption {
      title: string;
      year: number;
    }
    type Option = ObjectOption | string;
    
    interface MyInputProps {
      onKeyDown: (event: object) => void;
    }
    interface MyParams extends RenderInputParams {
      inputProps: MyInputProps;
    }
    
    export default function Tags() {
      const [value, setValue] = React.useState([top100Films[13]]);
      const handleKeyDown = event => {
        switch (event.key) {
          case ",":
          case " ": {
            event.preventDefault();
            event.stopPropagation();
            if (event.target.value.length > 0) {
              setValue([...value, event.target.value]);
            }
            break;
          }
          default:
        }
      };
      return (
        <div style={{ width: 500 }}>
          <Autocomplete
            multiple
            freeSolo
            id="tags-outlined"
            options={top100Films}
            getOptionLabel={option => {
              if (typeof option === "string") {
                return option;
              }
              return option.title;
            }}
            value={value}
            onChange={(event, newValue) => setValue(newValue)}
            filterSelectedOptions
            renderInput={(params: MyParams) => {
              params.inputProps.onKeyDown = handleKeyDown;
              return (
                <TextField
                  {...params}
                  variant="outlined"
                  label="filterSelectedOptions"
                  placeholder="Favorites"
                  margin="normal"
                  fullWidth
                />
              );
            }}
          />
        </div>
      );
    }
    
    // Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
    const top100Films: ObjectOption[] = [
      { title: "The Shawshank Redemption", year: 1994 },
      { title: "The Godfather", year: 1972 },
    // ... many more options
    ];
    
    

    【讨论】:

    • 您好,不幸的是,上述方法不起作用,至少使用 Typescript,因为 event.target.value 不存在。
    • @Sammy 抱歉,但我个人不使用 Typescript,所以对于如何在其中添加适当类型的建议我无能为力。
    • @Sammy 我今天开始学习 Typescript,所以我添加了一个 Typescript 版本。
    • 谢谢瑞恩!你也可以在这里查看我所做的:codesandbox.io/s/wild-sea-h2i0m
    【解决方案2】:

    作为answered here,只需使用autoHighlight 标志:

    <Autocomplete autoHighlight {...} />
    

    默认情况下它会突出显示第一个选项,因此按回车将选择它。

    【讨论】:

      猜你喜欢
      • 2013-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-23
      • 2021-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多