Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Material Ui Table Sort with pagination

I'm trying to get my table to sort via the different columns following the material UI documentation. I'm not sure why its not working but upon clicking on the header the sort order shows up and i can see everything firing it just not sorting. I believe i have a tiny error somewhere in my code and after staring at it for hours i cant seem to find it.

Material UI Table Documentation

Working CodeSandbox I'm trying to follow as well that matches the documentation: CodeSandbox

Code base:

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;
like image 544
Charles L. Avatar asked Jun 19 '20 16:06

Charles L.


1 Answers

As per your code, TableHead and TableBody are rendered with different ids.

  • Holiday name in TableHead has id = 'Holiday' but in TableBody, it is 'HolidayName'.

  • Holiday Date in TableHead has id = 'Date' but in TableBody, it is 'HolidayDate'.

You have to assign a similar string as id to TableHead and TableBody.

So try below changes to make sorting work

const headCells = [
  {
    id: "",
    numeric: false,
    disablePadding: true,
    label: ""
  },
  { id: "HolidayName", numeric: true, disablePadding: false, label: "Holiday" },
  { id: "HolidayDate", 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" },
];
like image 198
harish kumar Avatar answered Sep 28 '22 06:09

harish kumar