[英]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
另一种广泛的方法可以使用更复杂的组件来完成。 两个想法:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.