Я пытаюсь настроить свою таблицу для сортировки по различным столбцам, следуя документации пользовательского интерфейса материала. Я не уверен, почему он не работает, но при нажатии на заголовок появляется порядок сортировки, и я вижу, что все запускает его, но не сортирует. Я считаю, что где-то в моем коде есть крошечная ошибка, и, глядя на нее в течение нескольких часов, я не могу ее найти.
Документация по таблице пользовательского интерфейса материала
Рабочий код Sandbox I Я также пытаюсь следовать, что соответствует документации: CodeSandbox
База кода:
function TablePaginationActions(props) {
const theme = useTheme();
const { count, page, rowsPerPage, onChangePage } = props;
const handleFirstPageButtonClick = (event) => {
onChangePage(event, 0);
};
const handleBackButtonClick = (event) => {
onChangePage(event, page - 1);
};
const handleNextButtonClick = (event) => {
onChangePage(event, page + 1);
};
const handleLastPageButtonClick = (event) => {
onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));
};
return (
<div style={{ flexShrink: 0 }}>
<IconButton
onClick={handleFirstPageButtonClick}
disabled={page === 0}
aria-label="first page"
>
{theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
</IconButton>
<IconButton onClick={handleBackButtonClick} disabled={page === 0} aria-label="previous page">
{theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
</IconButton>
<IconButton
onClick={handleNextButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="next page"
>
{theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
</IconButton>
<IconButton
onClick={handleLastPageButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="last page"
>
{theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
</IconButton>
</div>
);
}
TablePaginationActions.propTypes = {
count: PropTypes.number.isRequired,
onChangePage: PropTypes.func.isRequired,
page: PropTypes.number.isRequired,
rowsPerPage: PropTypes.number.isRequired,
};
function descendingComparator(a, b, orderBy) {
if (b[orderBy] < a[orderBy]) {
return -1;
}
if (b[orderBy] > a[orderBy]) {
return 1;
}
return 0;
}
function getComparator(order, orderBy) {
return order === "desc"
? (a, b) => descendingComparator(a, b, orderBy)
: (a, b) => -descendingComparator(a, b, orderBy);
}
function stableSort(array, comparator) {
const stabilizedThis = array.map((el, index) => [el, index]);
stabilizedThis.sort((a, b) => {
const order = comparator(a[0], b[0]);
if (order !== 0) return order;
return a[1] - b[1];
});
return stabilizedThis.map(el => el[0]);
}
const headCells = [
{
id: "",
numeric: false,
disablePadding: true,
label: ""
},
{ id: "Holiday", numeric: true, disablePadding: false, label: "Holiday" },
{ id: "Date", numeric: true, disablePadding: false, label: "Date" },
{ id: "Branch", numeric: true, disablePadding: false, label: "Branch" },
{ id: "Hours", numeric: true, disablePadding: false, label: "Hours" },
{ id: "Web", numeric: true, disablePadding: false, label: "Web" },
{ id: "Phone", numeric: true, disablePadding: false, label: "Phone" },
{ id: "CoOp", numeric: true, disablePadding: false, label: "CoOp" },
{ id: "Submitted", numeric: true, disablePadding: false, label: "Submitted" },
{ id: "SubmittedBy", numeric: true, disablePadding: false, label: "SubmittedBy" },
{ id: "Published", numeric: true, disablePadding: false, label: "Published" },
{ id: "PublishedBy", numeric: true, disablePadding: false, label: "PublishedBy" },
];
const useStyles = makeStyles(theme => ({
visuallyHidden: {
border: 0,
clip: "rect(0 0 0 0)",
height: 1,
margin: -1,
overflow: "hidden",
padding: 0,
position: "absolute",
top: 20,
width: 1
}
}));
function EnhancedTableHead(props) {
const {
classes,
order,
orderBy,
onRequestSort
} = props;
const createSortHandler = property => event => {
onRequestSort(event, property);
};
return (
<TableHead>
<TableRow>
{headCells.map(headCell => (
<TableCell
key={headCell.id}
sortDirection={orderBy === headCell.id ? order : false}
>
<TableSortLabel
active={orderBy === headCell.id}
direction={orderBy === headCell.id ? order : "asc"}
onClick={createSortHandler(headCell.id)}
>
{headCell.label}
{orderBy === headCell.id ? (
<span className={classes.visuallyHidden}>
{order === "desc" ? "sorted descending" : "sorted ascending"}
</span>
) : null}
</TableSortLabel>
</TableCell>
))}
</TableRow>
</TableHead>
);
}
const HolidaySettings = () => {
const classes = useStyles();
const [loading, setLoading] = useState(true);
const [open, setOpen] = React.useState(false);
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(5);
const anchorRef = React.useRef(null);
const [dialogOpen, setDialogOpen] = React.useState(false);
const [dialogData, setDialogData] = React.useState({});
const [showInactive, setShowInactive] = useState(false);
const [searchResults, setSearchResults] = useState([]);
const [order, setOrder] = React.useState("asc");
const [orderBy, setOrderBy] = React.useState("Holiday");
const dispatch = useDispatch();
const onInit = useCallback(() => {
dispatch(actions.holiday_getHolidays());
dispatch(actions.holiday_getProductionHolidays());
}, [dispatch]);
useEffect(() => {
if (loading) {
onInit();
}
}, [loading]);
const rows = useSelector(state => {
let results = [];
if (showInactive) {
results = state.holidays.holidays;
} else {
results = state.holidays.activeHolidays;
}
if (state.holidays.holidays && loading) {
setLoading(false);
setSearchResults(results);
}
return results;
});
const handleRequestSort = (event, property) => {
const isAsc = orderBy === property && order === "asc";
setOrder(isAsc ? "desc" : "asc");
setOrderBy(property);
};
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen);
};
const handleDialogOpen = (dataElement) => {
setDialogData(dataElement);
setDialogOpen(true);
setOpen(false);
}
const handleHolidayDelete = (dataElement) => {
dispatch(actions.holiday_deleteHoliday(dataElement));
}
const handleDialogClose = () => {
setOpen(false);
setDialogOpen(false);
};
const handleClose = (event) => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
const handleInactiveChange = (e) => {
e.persist();
const { checked } = e.target;
setShowInactive(checked)
}
const handleSearch = (e) => {
e.persist();
const searchValue = e.target.value;
let results = _.map(rows, function(holiday) {
if (holiday.HolidayName.toLowerCase().indexOf(searchValue.toLowerCase()) !== -1) return holiday;
});
results = _.without(results, undefined);
setSearchResults(results);
}
return (
<div>
<div className="row">
<div className="col">
<div className="card-chart card">
<div className="card-header">
<div className="row">
<div className="col-sm-12 d-flex">
<h4 className="card-title">Holiday Settings</h4>
<div
className="ml-auto mr-5"
ref={anchorRef}
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}>
<SettingsOutlinedIcon style={{ fontSize: 20 }} />
{open ? (
<ExpandLess style={{ fontSize: 12 }} />
) : (
<ExpandMore style={{ fontSize: 12 }} />
)}
</div>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow">
<MenuItem onClick={handleDialogOpen}>Add Holiday</MenuItem>
<MenuItem>
<FormControlLabel className=""
label="Show Inactive"
control={
<Checkbox
checked={showInactive || false}
value={showInactive}
onChange={handleInactiveChange}
name="Show Inactive"
color="primary"
/>
}
/>
</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
</div>
</div>
{loading ? (
<CanvasLoader loading={loading} />
) : (
<div className="card-body">
<div className="text-left col-12">
<Paper>
<TextField id="standard-basic" label="Search" onChange={handleSearch}/>
<TableContainer component={Paper} className="holidaysTableContainer">
<Table className="w-100" aria-label="simple table">
<EnhancedTableHead
classes={classes}
order={order}
orderBy={orderBy}
onRequestSort={handleRequestSort}
rowCount={rows.length}
/>
<TableBody>
{stableSort(searchResults, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row, index) => {
return (
<TableRow key={row.RowId} id={row.Id} className={row.Active ? '' : 'inactive-row'}>
<TableCell>{<div className="d-flex flex-align-center justify-content-center"><CreateOutlinedIcon className="holidayEditIcon" style={{ color: '#00f2c3' }} onClick={() => { handleDialogOpen(row); }} /> {row.Active ? (<DeleteForeverOutlinedIcon className="holidayDeleteIcon" style={{ color: '#fd5d93' }} onClick={() => { handleHolidayDelete(row); }} />) : (<div></div>)}</div>}</TableCell>
<TableCell>{row.HolidayName}</TableCell>
<TableCell>{moment(row.HolidayDate).format('ddd, MMM Do YYYY')}</TableCell>
<TableCell>{row.Branch ? row.Branch : 'All'}</TableCell>
<TableCell>{row.Hours ? row.Hours : 'Closed'}</TableCell>
<TableCell>{(row.Web ? <DoneIcon style={{ color: '#00f2c3' }} value="true" /> : <CloseIcon style={{ color: '#fd5d93' }} value="false" />)}</TableCell>
<TableCell>{(row.Phone ? <DoneIcon style={{ color: '#00f2c3' }} value="true" /> : <CloseIcon style={{ color: '#fd5d93' }} value="false" />)}</TableCell>
<TableCell>{(row.CoOp ? <DoneIcon style={{ color: '#00f2c3' }} value="true" /> : <CloseIcon style={{ color: '#fd5d93' }} value="false" />)}</TableCell>
<TableCell>{(row.Submitted ? moment(row.Submitted).format('MMM Do, YYYY') : false)}</TableCell>
<TableCell>{row.SubmittedBy}</TableCell>
<TableCell>{(row.Published ? moment(row.Published).format('MMM Do, YYYY') : false)}</TableCell>
<TableCell>{row.PublishedBy}</TableCell>
</TableRow>
)
})}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
colSpan={12}
count={searchResults.length}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
ActionsComponent={TablePaginationActions}
/>
</TableRow>
</TableFooter>
</Table>
</TableContainer>
</Paper>
<HolidayDialog open={dialogOpen} onClose={handleDialogClose} data={dialogData} />
</div>
</div>
)}
</div>
</div>
</div>
</div>
)
}
export default HolidaySettings;