1

I am trying to hide columns in a MUI table on smaller screen sizes. I'm following the documentation exactly but getting wonky results. Wondering if anyone has a solution or a workaround.

import * as React from 'react';
import PropTypes from 'prop-types';
import Box from '@mui/material/Box';
import Collapse from '@mui/material/Collapse';
import IconButton from '@mui/material/IconButton';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Typography from '@mui/material/Typography';
import Paper from '@mui/material/Paper';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';

function createData(name, calories, fat, carbs, protein, price) {
  return {
    name,
    calories,
    fat,
    carbs,
    protein,
    price,
    history: [
      {
        date: '2020-01-05',
        customerId: '11091700',
        amount: 3,
      },
      {
        date: '2020-01-02',
        customerId: 'Anonymous',
        amount: 1,
      },
    ],
  };
}

function Row(props) {
  const { row } = props;
  const [open, setOpen] = React.useState(false);

  return (
    <React.Fragment>
      <TableRow sx={{ '& > *': { borderBottom: 'unset' }}}>
        <TableCell>
          <IconButton
            aria-label="expand row"
            size="small"
            onClick={() => setOpen(!open)}
          >
            {open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
          </IconButton>
        </TableCell>
        <TableCell component="th" scope="row">
          {row.name}
        </TableCell>
        <TableCell align="right"  sx={{ display: { xs: 'none', sm: 'block' } }}>{row.calories}</TableCell>
        <TableCell align="right">{row.fat}</TableCell>
        <TableCell align="right">{row.carbs}</TableCell>
        <TableCell align="right">{row.protein}</TableCell>
      </TableRow>
      <TableRow>
        <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
          <Collapse in={open} timeout="auto" unmountOnExit>
            <Box sx={{ margin: 1 }}>
              <Typography variant="h6" gutterBottom component="div">
                History
              </Typography>
              <Table size="small" aria-label="purchases">
                <TableHead>
                  <TableRow>
                    <TableCell>Date</TableCell>
                    <TableCell>Customer</TableCell>
                    <TableCell align="right">Amount</TableCell>
                    <TableCell align="right">Total price ($)</TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {row.history.map((historyRow) => (
                    <TableRow key={historyRow.date}>
                      <TableCell component="th" scope="row">
                        {historyRow.date}
                      </TableCell>
                      <TableCell>{historyRow.customerId}</TableCell>
                      <TableCell align="right">{historyRow.amount}</TableCell>
                      <TableCell align="right">
                        {Math.round(historyRow.amount * row.price * 100) / 100}
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </Box>
          </Collapse>
        </TableCell>
      </TableRow>
    </React.Fragment>
  );
}

Row.propTypes = {
  row: PropTypes.shape({
    calories: PropTypes.number.isRequired,
    carbs: PropTypes.number.isRequired,
    fat: PropTypes.number.isRequired,
    history: PropTypes.arrayOf(
      PropTypes.shape({
        amount: PropTypes.number.isRequired,
        customerId: PropTypes.string.isRequired,
        date: PropTypes.string.isRequired,
      }),
    ).isRequired,
    name: PropTypes.string.isRequired,
    price: PropTypes.number.isRequired,
    protein: PropTypes.number.isRequired,
  }).isRequired,
};

const rows = [
  createData('Frozen yoghurt', 159, 6.0, 24, 4.0, 3.99),
  createData('Ice cream sandwich', 237, 9.0, 37, 4.3, 4.99),
  createData('Eclair', 262, 16.0, 24, 6.0, 3.79),
  createData('Cupcake', 305, 3.7, 67, 4.3, 2.5),
  createData('Gingerbread', 356, 16.0, 49, 3.9, 1.5),
];

export default function CollapsibleTable() {
  return (
    <TableContainer component={Paper}>
      <Table aria-label="collapsible table" >
        <TableHead>
          <TableRow>
            <TableCell />
            <TableCell>Dessert (100g serving)</TableCell>
            <TableCell align="right" sx={{ display: { xs: 'none', sm: 'block' } }}>Calories</TableCell>
            <TableCell align="right">Fat&nbsp;(g)</TableCell>
            <TableCell align="right">Carbs&nbsp;(g)</TableCell>
            <TableCell align="right">Protein&nbsp;(g)</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {rows.map((row) => (
            <Row key={row.name} row={row} />
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
}

unfortunately the sx={{ display: { xs: 'none', sm: 'block' } is giving me this result on desktop:

screenshot

It is hiding the rows on smaller screens, but as you can see it is fragmenting the dividers on desktop (and pushing the divider on the column header up a tiny bit).

juliomalves
  • 42,130
  • 20
  • 150
  • 146
Colin S
  • 123
  • 7
  • Did you try any other value? `block` seems like an odd choice. My first guess would be `table-cell`. – super Oct 04 '22 at 21:12

2 Answers2

3

You need to replace this style:

sx={{ display: { xs: 'none', sm: 'block' }

with this style:

sx={{ display: { xs: 'none', sm: 'table-cell' }

in both header and body TableCell because its default value is table-cell.

You can take a look at this sandbox for a live working example.

Ahmet Emre Kilinc
  • 5,489
  • 12
  • 30
  • 42
  • Thanks Ahmet. This didn't work for me but helped me figure out the answer. For anyone wondering it did work when I replaced 'table-cell' with 'revert' – Colin S Oct 05 '22 at 15:04
0

If you get here for angular answer. There it is. Put this code: In html (adapt to your code):

<mat-header-row *matHeaderRowDef="getDisplayedColumns()"></mat-header-row>
<mat-row *matRowDef="let row; columns: getDisplayedColumns()"></mat-row>
<mat-footer-row *matFooterRowDef="getDisplayedColumns()"></mat-footer-row>

In the .ts Make your class implements OnInit e OnDestroy

Declare these methods

 isPortrait() {
    return !this.landscape.matches;
  }  
  handlerOrientation: any;

//https://code.daypilot.org/79036/angular-calendar-detect-orientation-change-landscape-portrait landscape = window.matchMedia("(orientation: landscape)");

  ngOnDestroy(): void {
    console.log('on destroy');
    //https://stackoverflow.com/questions/46906763/how-to-remove-eventlisteners-in-angular-4
    //https://code.daypilot.org/79036/angular-calendar-detect-orientation-change-landscape-portrait
    this.landscape.removeEventListener("change", this.handlerOrientation, true);
  }

  private onChangeOrientation() {
    console.log('landscape orientation');
  }

  //https://code.daypilot.org/79036/angular-calendar-detect-orientation-change-landscape-portrait
  landscape = window.matchMedia("(orientation: landscape)");

//https://stackoverflow.com/questions/47077302/angular2-material-table-hide-column
//https://stackoverflow.com/questions/41432533/how-to-detect-if-device-is-desktop-and-or-mobile-and-if-connection-is-wifi-or-n
   getDisplayedColumns() : string[] {
            let exibir = !this.isPortrait();
            return this.displayedColumns.filter(cd => exibir || cd.showMobile).map(cd => cd.def);}

Declare the columns this way

  displayedColumns = [{ def: 'data', showMobile: true}, { def: 'numero', showMobile: false}];

}

In OnInit put this

this.handlerOrientation = this.onChangeOrientation.bind(this);
this.landscape.addEventListener("change", this.handlerOrientation, true);