繁体   English   中英

React 中的自定义自动完成验证

[英]Custom autocomplete validation in React

我创建了一个自定义自动完成下拉列表,但我需要强制用户从列表中输入 select 的内容,同时保持在输入字段中输入内容的可能性。

如何创建这样的验证? 自动完成组件是一个列表,可以从 API 中获得 select,但用户仍然可以在输入字段中键入任何内容并发送它。 我希望用户只能使用建议的项目提交表单。 你能帮我做一个吗?

基本上问题是:如何检查输入值是否与从自动完成组件中获取的项目相同?

export type AutocompletePropsType = {
  inputValue: string;
  currentIndex: number;
  onSelect: (selectedItem: string, slug?: string | null) => void;
  hasError: boolean;
  list: AutocompleteResponse['data'];
};

type PropsType = {
  onChange: (value: string, type: string, isValid?: boolean, slug?: string) => void;
  inputName: string;
  type: InputType;
  label: string;
  autocompleteComponent: React.ComponentType<AutocompletePropsType>;
  validator?: UseFieldValidatorType;
};

const SearchInput = (props: PropsType): JSX.Element => {
  const { onChange, inputName, type, label, autocompleteComponent: AutocompleteComponent, validator } = props;
  const autocompleteRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  const classes = useStyles();
  const router = useRouter();

  const dispatch = useDispatch();
  const [currentIdx, setCurrentIdx] = useState(-1);

  const [state, { handleInputBlur, handleInputChange, handleInputFocus }] = useField({
    inputValidator: validator,
  });

  const { isFocused, isValid, value } = state;

  const [list, { hasError }] = useAutocomplete<AutocompleteResponse['data']>(value, async (query: string) =>
    searchApi.autocomplete[type](query).then((res) => (res.data as unknown) as AutocompleteResponse['data']),
  );

  const handleSelect = (alias: string): void => {
    handleInputChange(alias);
    onChange(alias, type);
    handleInputBlur();
  };

  const handleFocus = (): void => {
    handleInputFocus();
    inputRef.current.focus();
  };

  const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
    handleInputChange(event);
    const isValueValid = validator ? validator(event.target.value).success : true;

    onChange(event.target.value, event.target.name, isValueValid);
  };

  useClickOutside(autocompleteRef, () => {
    handleInputBlur();
  });

  useEffect(() => {
    (async (): Promise<void> => {
      if (router.pathname !== '/' && !value) {
        const { alias, slug } = await getInitialInputValuesFromQuery(router, type);

        handleInputChange(alias);
        onChange(alias, type, isValid, slug);
      }
    })();
  }, []);

  return (
    <div className={classes['search-input']} ref={autocompleteRef}>
      <div onClick={handleFocus}>
        <label
          className={cx(classes['search-input__input__label'], {
            [classes['search-input__input__label--active']]: isFocused || !!value,
          })}
        >
          {label}
        </label>
        <input
          id={inputName}
          onChange={handleChange}
          onFocus={handleInputFocus}
          name={inputName}
          value={value}
          className={classes['search-input__input__field']}
          autoComplete="off"
          checked={false}
          ref={inputRef}
          maxLength={25}
        />
        <div
          className={cx(classes['input__decorator'], {
            [classes['input__decorator--focused']]: isFocused,
          })}
        />
      </div>
      {transitions(
        ({ transform, opacity }, item) =>
          item && (
            <animated.div className={classes['search-input__dropdown']} style={{ opacity: opacity as any, transform }}>
              {value.length > 2 && (
                <AutocompleteComponent
                  onSelect={handleSelect}
                  inputValue={value}
                  currentIndex={currentIdx}
                  hasError={hasError}
                  list={list}
                />
              )}
            </animated.div>
          ),
      )}
    </div>
  );
};

export default SearchInput;

免责声明:我没有完全阅读代码,因为那里有一些我还不理解的东西(打字稿)。 但考虑到这一点:

自动完成组件是一个列表

如何检查输入值是否与从自动完成中获取的项目相同

在发送表单之前,您可以使用Array.prototype.includes()将用户输入与您的列表相匹配。

let userInput = "foo"
let userInput2 = "opsIAmInvalid"

let apiList = ["foo", "doo", "boo"]

apiList.includes(userInput) // true
apiList.includes(userInput2) // false

另一种广泛的方法可以使用更复杂的组件来完成。 两个想法:

  1. 两个输入,一个是过滤列表的用户文本,另一个是从列表中选择的实际项目。 发送表单时忽略的第一个,您可以使用一些焦点验证来更改 styles。 (我不喜欢这个想法:x)
  2. 一个输入,您的用户键入任何过滤列表的内容。 当他们从列表中单击某些内容时,您将其保存为变量/状态。 您忽略提交时的输入,只需验证变量/状态是否存在。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM