在自动完成字段中验证电子邮件地址
Validate email address within autocomplete field
我正在使用 Material UI 创建一个具有多个输入的自动完成字段,允许用户 select 现有的电子邮件地址,或输入他们自己的。例如,像这样:
现在,用户可以成功输入他们的电子邮件地址,或 select 从下拉菜单中输入一个 - 本质上与上面的链接示例相同。
但是,我现在正在尝试进行电子邮件验证,以便发生一些事情:
- 按下“回车”键后,我检查电子邮件是否有效。如果不是,则应向用户显示一条错误消息 并且 输入的电子邮件地址未添加到 运行 列表
- 只要出现错误,任何后续操作(退格键、键入、单击“X”等)都应删除错误消息
截至目前,我能够按照上面的第 1 点验证电子邮件地址,但我不确定如何在用户点击“输入”键时阻止将值添加到列表中。此外,要删除错误消息,我只能在用户键入或删除其他字符时这样做(即通过 onChange
方法)。但是,如果用户与 Autocomplete
组件进行交互(例如,单击“X”以删除电子邮件地址),错误仍然显示。
这是我目前拥有的:
import React, { useState } from "react";
import Chip from "@mui/material/Chip";
import Autocomplete from "@mui/material/Autocomplete";
import TextField from "@mui/material/TextField";
import Stack from "@mui/material/Stack";
export default function Tags() {
const [emails, setEmails] = useState([]);
const [currValue, setCurrValue] = useState(undefined);
const regex = /^(([^<>()\[\]\.,;:\s@"]+(\.[^<>()\[\]\.,;:\s@"]+)*)|(".+"))@((([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const [error, setError] = useState(false);
const emailAddresses = [
{ title: "test_email_1@gmail.com" },
{ title: "test_email_2@gmail.com" },
{ title: "test_email_3@gmail.com" }
];
const handleValidation = (e) => {
// check if the user has hit the "enter" key (which is code "13")
if (e.keyCode === 13 && !regex.test(e.target.value)) {
setError(true);
}
};
const handleChange = (e) => {
// anytime the user makes a modification, remove any errors
setError(false);
setCurrValue(e.target.value);
};
console.log("emails", emails);
return (
<Stack spacing={3} sx={{ width: 500 }}>
<Autocomplete
multiple
onChange={(event, value) => setEmails(value)}
id="tags-filled"
options={emailAddresses.map((option) => option.title)}
freeSolo
renderTags={(value: readonly string[], getTagProps) =>
value.map((option: string, index: number) => (
<Chip
variant="outlined"
label={option}
{...getTagProps({ index })}
/>
))
}
renderInput={(params) => (
<TextField
{...params}
variant="filled"
label="Email Addresses"
placeholder="Favorites"
type="email"
value={currValue}
onChange={handleChange}
onKeyDown={handleValidation}
error={error}
helperText={error && "Please enter a valid email address"}
/>
)}
/>
</Stack>
);
}
Code Sandbox 的示例在这里:https://codesandbox.io/s/tags-material-demo-forked-5l7ovu?file=/demo.tsx
注意:我不完全确定如何在 Stack Overflow 上提供可复制的代码,因此对于将我的代码链接到 Code Sandbox 提前表示歉意。
您需要使用 controlled autocomplete。在 onChange
中我们需要做 -
如果有任何无效的电子邮件,将其从数组中删除并将状态更新为有效的电子邮件。 (筹码)
我们仍然需要将无效的电子邮件显示为文本(不是芯片),为此我们可以设置 inputValue
。 (正文)
设置或删除错误。
function onChange(e, value) {
// error
const errorEmail = value.find((email) => !regex.test(email));
if (errorEmail) {
// set value displayed in the textbox
setInputValue(errorEmail);
setError(true);
} else {
setError(false);
}
// Update state, only valid emails
setSelected(value.filter((email) => regex.test(email)));
}
由于它的控制,我们还需要处理芯片的onDelete
&更新状态。完整代码和工作 codesandbox
export default function Tags() {
const [selected, setSelected] = useState([]);
const [inputValue, setInputValue] = useState("");
const regex = /^(([^<>()\[\]\.,;:\s@"]+(\.[^<>()\[\]\.,;:\s@"]+)*)|(".+"))@((([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const [error, setError] = useState(false);
const emailAddresses = [
{ title: "a@gmail.com" },
{ title: "b@gmail.com" },
{ title: "c@gmail.com" }
];
function onChange(e, value) {
// error
const errorEmail = value.find((email) => !regex.test(email));
if (errorEmail) {
// set value displayed in the textbox
setInputValue(errorEmail);
setError(true);
} else {
setError(false);
}
// Update state
setSelected(value.filter((email) => regex.test(email)));
}
function onDelete(value) {
setSelected(selected.filter((e) => e !== value));
}
function onInputChange(e, newValue) {
setInputValue(newValue);
}
return (
<Stack spacing={3} sx={{ width: 500 }}>
<Autocomplete
multiple
onChange={onChange}
id="tags-filled"
value={selected}
inputValue={inputValue}
onInputChange={onInputChange}
options={emailAddresses.map((option) => option.title)}
freeSolo
renderTags={(value: readonly string[], getTagProps) =>
value.map((option: string, index: number) => (
<Chip
variant="outlined"
label={option}
{...getTagProps({ index })}
onDelete={() => onDelete(option)} //delete
/>
))
}
renderInput={(params) => (
<TextField
....
/>
)}
/>
</Stack>
);
}
我正在使用 Material UI 创建一个具有多个输入的自动完成字段,允许用户 select 现有的电子邮件地址,或输入他们自己的。例如,像这样:
现在,用户可以成功输入他们的电子邮件地址,或 select 从下拉菜单中输入一个 - 本质上与上面的链接示例相同。
但是,我现在正在尝试进行电子邮件验证,以便发生一些事情:
- 按下“回车”键后,我检查电子邮件是否有效。如果不是,则应向用户显示一条错误消息 并且 输入的电子邮件地址未添加到 运行 列表
- 只要出现错误,任何后续操作(退格键、键入、单击“X”等)都应删除错误消息
截至目前,我能够按照上面的第 1 点验证电子邮件地址,但我不确定如何在用户点击“输入”键时阻止将值添加到列表中。此外,要删除错误消息,我只能在用户键入或删除其他字符时这样做(即通过 onChange
方法)。但是,如果用户与 Autocomplete
组件进行交互(例如,单击“X”以删除电子邮件地址),错误仍然显示。
这是我目前拥有的:
import React, { useState } from "react";
import Chip from "@mui/material/Chip";
import Autocomplete from "@mui/material/Autocomplete";
import TextField from "@mui/material/TextField";
import Stack from "@mui/material/Stack";
export default function Tags() {
const [emails, setEmails] = useState([]);
const [currValue, setCurrValue] = useState(undefined);
const regex = /^(([^<>()\[\]\.,;:\s@"]+(\.[^<>()\[\]\.,;:\s@"]+)*)|(".+"))@((([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const [error, setError] = useState(false);
const emailAddresses = [
{ title: "test_email_1@gmail.com" },
{ title: "test_email_2@gmail.com" },
{ title: "test_email_3@gmail.com" }
];
const handleValidation = (e) => {
// check if the user has hit the "enter" key (which is code "13")
if (e.keyCode === 13 && !regex.test(e.target.value)) {
setError(true);
}
};
const handleChange = (e) => {
// anytime the user makes a modification, remove any errors
setError(false);
setCurrValue(e.target.value);
};
console.log("emails", emails);
return (
<Stack spacing={3} sx={{ width: 500 }}>
<Autocomplete
multiple
onChange={(event, value) => setEmails(value)}
id="tags-filled"
options={emailAddresses.map((option) => option.title)}
freeSolo
renderTags={(value: readonly string[], getTagProps) =>
value.map((option: string, index: number) => (
<Chip
variant="outlined"
label={option}
{...getTagProps({ index })}
/>
))
}
renderInput={(params) => (
<TextField
{...params}
variant="filled"
label="Email Addresses"
placeholder="Favorites"
type="email"
value={currValue}
onChange={handleChange}
onKeyDown={handleValidation}
error={error}
helperText={error && "Please enter a valid email address"}
/>
)}
/>
</Stack>
);
}
Code Sandbox 的示例在这里:https://codesandbox.io/s/tags-material-demo-forked-5l7ovu?file=/demo.tsx
注意:我不完全确定如何在 Stack Overflow 上提供可复制的代码,因此对于将我的代码链接到 Code Sandbox 提前表示歉意。
您需要使用 controlled autocomplete。在 onChange
中我们需要做 -
如果有任何无效的电子邮件,将其从数组中删除并将状态更新为有效的电子邮件。 (筹码)
我们仍然需要将无效的电子邮件显示为文本(不是芯片),为此我们可以设置
inputValue
。 (正文)设置或删除错误。
function onChange(e, value) {
// error
const errorEmail = value.find((email) => !regex.test(email));
if (errorEmail) {
// set value displayed in the textbox
setInputValue(errorEmail);
setError(true);
} else {
setError(false);
}
// Update state, only valid emails
setSelected(value.filter((email) => regex.test(email)));
}
由于它的控制,我们还需要处理芯片的onDelete
&更新状态。完整代码和工作 codesandbox
export default function Tags() {
const [selected, setSelected] = useState([]);
const [inputValue, setInputValue] = useState("");
const regex = /^(([^<>()\[\]\.,;:\s@"]+(\.[^<>()\[\]\.,;:\s@"]+)*)|(".+"))@((([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const [error, setError] = useState(false);
const emailAddresses = [
{ title: "a@gmail.com" },
{ title: "b@gmail.com" },
{ title: "c@gmail.com" }
];
function onChange(e, value) {
// error
const errorEmail = value.find((email) => !regex.test(email));
if (errorEmail) {
// set value displayed in the textbox
setInputValue(errorEmail);
setError(true);
} else {
setError(false);
}
// Update state
setSelected(value.filter((email) => regex.test(email)));
}
function onDelete(value) {
setSelected(selected.filter((e) => e !== value));
}
function onInputChange(e, newValue) {
setInputValue(newValue);
}
return (
<Stack spacing={3} sx={{ width: 500 }}>
<Autocomplete
multiple
onChange={onChange}
id="tags-filled"
value={selected}
inputValue={inputValue}
onInputChange={onInputChange}
options={emailAddresses.map((option) => option.title)}
freeSolo
renderTags={(value: readonly string[], getTagProps) =>
value.map((option: string, index: number) => (
<Chip
variant="outlined"
label={option}
{...getTagProps({ index })}
onDelete={() => onDelete(option)} //delete
/>
))
}
renderInput={(params) => (
<TextField
....
/>
)}
/>
</Stack>
);
}