如何解决材质用户界面自动完成:无法将嵌套数组数据填充为单独的标签选项
我有来自API的数据,其格式如下:
const companies = [
{ type: "Banks",names: ["CIBC","RBC","BMO"] },{ type: "E-Banks",names: ["Oaken","XYZ","EQ"] },{ type: "Credit Unions",names: ["ABC","TTB"] }
];
在Material UI的自动完成功能中,我希望能够将'type'属性填充为有效的groupBy标题,但是我无法弄清楚如何在选项中填充这些'名称'。
沙箱在这里:https://codesandbox.io/s/material-demo-forked-oo3td?file=/demo.js
我的自动填充组件如下:
<Autocomplete
open
onClose={handleClose}
multiple
value={pendingValue}
onChange={(event,newValue) => {
setPendingValue(newValue);
}}
disableCloseOnSelect
disablePortal
//renderTags={() => null}
noOptionsText="No labels"
renderOption={(option,{ selected }) => (
<>
<DoneIcon
//className={classes.iconSelected}
style={{ visibility: selected ? "visible" : "hidden" }}
/>
{/* how to map below */}
<div className={classes.text}>{[...option.names]}</div>
<CloseIcon
//className={classes.close}
style={{ visibility: selected ? "visible" : "hidden" }}
/>
</>
)}
options={[...companies].sort((a,b) => {
// Display the selected labels first.
let ai = value.indexOf(a);
ai = ai === -1 ? value.length + companies.indexOf(a) : ai;
let bi = value.indexOf(b);
bi = bi === -1 ? value.length + companies.indexOf(b) : bi;
return ai - bi;
})}
groupBy={(option) => option.type}
getOptionLabel={(option) => option.names[0]} //how to map here
renderInput={(params) => (
<InputBase
ref={params.InputProps.ref}
inputProps={params.inputProps}
autoFocus
className={classes.inputBase}
/>
)}
/>
我尝试将名称分散在renderOption属性中,但是在自动拼写中,它只将所有选项填充到一行中,这是有意义的,因为它是选项的一部分。我无法弄清楚如何将其放在单独的行中以及能够分别选择它们。
解决方法
为什么不以适当的格式重新格式化API响应(只需清理代码,放在单独的函数中即可。)?
/* eslint-disable no-use-before-define */
import React from "react";
import { fade,makeStyles } from "@material-ui/core/styles";
import Popper from "@material-ui/core/Popper";
import SettingsIcon from "@material-ui/icons/Settings";
import CloseIcon from "@material-ui/icons/Close";
import DoneIcon from "@material-ui/icons/Done";
import Autocomplete from "@material-ui/lab/Autocomplete";
import ButtonBase from "@material-ui/core/ButtonBase";
import InputBase from "@material-ui/core/InputBase";
import Chip from "@material-ui/core/Chip";
const useStyles = makeStyles((theme) => ({
root: {
width: 221,fontSize: 13
},button: {
fontSize: 13,width: "100%",textAlign: "left",paddingBottom: 8,color: "#586069",fontWeight: 600,"&:hover,&:focus": {
color: "#0366d6"
},"& span": {
width: "100%"
},"& svg": {
width: 16,height: 16
}
},tag: {
marginTop: 3
},popper: {
border: "1px solid rgba(27,31,35,.15)",boxShadow: "0 3px 12px rgba(27,borderRadius: 3,width: 300,zIndex: 1,fontSize: 13,backgroundColor: "#f6f8fa"
},header: {
borderBottom: "1px solid #e1e4e8",padding: "8px 10px",fontWeight: 600
},inputBase: {
padding: 10,borderBottom: "1px solid #dfe2e5","& input": {
borderRadius: 4,backgroundColor: theme.palette.common.white,padding: 8,transition: theme.transitions.create(["border-color","box-shadow"]),border: "1px solid #ced4da",fontSize: 14,"&:focus": {
boxShadow: `${fade(theme.palette.primary.main,0.25)} 0 0 0 0.2rem`,borderColor: theme.palette.primary.main
}
}
},paper: {
boxShadow: "none",margin: 0,option: {
minHeight: "auto",alignItems: "flex-start",'&[aria-selected="true"]': {
backgroundColor: "transparent"
},'&[data-focus="true"]': {
backgroundColor: theme.palette.action.hover
}
},popperDisablePortal: {
position: "relative"
},iconSelected: {
width: 17,height: 17,marginRight: 5,marginLeft: -2
},color: {
width: 14,height: 14,flexShrink: 0,marginRight: 8,marginTop: 2
},text: {
flexGrow: 1
},close: {
opacity: 0.6,width: 18,height: 18
}
}));
export default function GitHubLabel() {
const classes = useStyles();
const [anchorEl,setAnchorEl] = React.useState(null);
const [value,setValue] = React.useState([]);
const [pendingValue,setPendingValue] = React.useState([]);
const handleClick = (event) => {
setPendingValue(value);
setAnchorEl(event.currentTarget);
};
// Reformat API response JSON
const reformatedCompanies = companies.reduce((akku,row) => {
const companyRows = [];
row.names.map((name) => {
companyRows.push({
type: row.type,name: name
});
});
akku = akku.concat(companyRows);
return akku;
},[]);
// Till here
const handleDelete = (name) => {
const newValue = value.filter((company) => company.name !== name);
setValue(newValue);
};
const handleClose = (event,reason) => {
if (reason === "toggleInput") {
return;
}
setValue(pendingValue);
if (anchorEl) {
anchorEl.focus();
}
setAnchorEl(null);
};
const open = Boolean(anchorEl);
return (
<React.Fragment>
<div className={classes.root}>
<ButtonBase
disableRipple
className={classes.button}
//aria-describedby={id}
onClick={handleClick}
>
<span>Companies</span>
<SettingsIcon />
</ButtonBase>
{value.map((company,index) => (
<Chip
key={company.name}
label={company.name}
onDelete={() => handleDelete(company.name)}
color="primary"
className={classes.tag}
/>
))}
</div>
<Popper
//id={id}
open={open}
anchorEl={anchorEl}
placement="bottom-start"
className={classes.popper}
>
<div className={classes.header}>Search companies</div>
<Autocomplete
open
onClose={handleClose}
multiple
value={pendingValue}
onChange={(event,newValue) => {
setPendingValue(newValue);
}}
disableCloseOnSelect
disablePortal
//renderTags={() => null}
noOptionsText="No labels"
renderOption={(option,{ selected }) => (
<>
<DoneIcon
//className={classes.iconSelected}
style={{ visibility: selected ? "visible" : "hidden" }}
/>
{/* how to map below */}
<div className={classes.text}>{[...option.name]}</div>
<CloseIcon
//className={classes.close}
style={{ visibility: selected ? "visible" : "hidden" }}
/>
</>
)}
options={reformatedCompanies}
groupBy={(option) => option.type}
getOptionLabel={(option) => option.name} //how to map here
renderInput={(params) => (
<InputBase
ref={params.InputProps.ref}
inputProps={params.inputProps}
autoFocus
className={classes.inputBase}
/>
)}
/>
</Popper>
</React.Fragment>
);
}
const companies = [
{ type: "Banks",names: ["CIBC","RBC","BMO"] },{ type: "E-Banks",names: ["Oaken","XYZ","EQ"] },{ type: "Credit Unions",names: ["ABC","TTB"] }
];
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。