user7494097
user7494097

Reputation:

How to group table in reactjs?

I am using the Table control from material UI to display the data , but right now I have the requirement to show the group data,with expand and collapsed data.Is there any package present to achieve this goal?Please assist me.

import { TableRowProps, Table, TableBody, TableFooter, PagiFooter, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table';
 <Table>
  <TableHeader {...headerProps}>
  {this.renderHeaders()}
  </TableHeader>
  <TableBody displayRowCheckbox={false}
  deselectOnClickaway={false}>
  {this.renderRows()}
  </TableBody>
</Table>

Upvotes: 1

Views: 9125

Answers (4)

Cleber Pinheiro Ramos
Cleber Pinheiro Ramos

Reputation: 11

    function createData(name, calories, fat, carbs, protein) {
  return { name, calories, fat, carbs, protein };
}

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

const DataCard = ({ show }) => {
  const classes = useStyles();

  const [open, setOpen] = useState();

  const handleExpandedClick = index => (e) => {
    setOpen(index === open ? '' : index);
  }

  return (
    <Only when={show}>
      <Paper className={classes.root}>
        <Table className={classes.table}>
          <TableHead>
            <TableRow>
              <TableCell>Dessert (100g serving)</TableCell>
              <TableCell align="right">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, index) => (

              <>
                <TableRow
                  key={index}
                  hover
                  style={{ cursor: 'pointer' }}
                  onClick={handleExpandedClick(index)}
                >
                  <TableCell component="th" scope="row">{row.name}</TableCell>
                  <TableCell align="right">{row.calories}</TableCell>
                  <TableCell align="right">{row.fat}</TableCell>
                  <TableCell align="right">{row.carbs}</TableCell>
                  <TableCell align="right">{row.protein}</TableCell>
                </TableRow>
                <Collapse in={open === index} hidden={open !== index} component="tr" style={{ display: "block" }}>
                  <td>
                    <div>Expanded data.</div>
                  </td>
                </Collapse>
              </>
            ))}
          </TableBody>
        </Table>
      </Paper>
    </Only>
  )
}

DataCard.propTypes = {
  show: PropTypes.bool.isRequired
}

export default DataCard;

Upvotes: 1

Aathi
Aathi

Reputation: 3224

Thank you @bluehipy, I have managed rewrite the code with hooks

import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import Collapse from "@material-ui/core/Collapse";
import CardActions from "@material-ui/core/CardActions";
import IconButton from "@material-ui/core/IconButton";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";

import getOrdersBasedOnRouteQuery from "../graphql/queries/getOrdersBasedOnRouteQuery";

const styles = theme => ({
  root: {
    width: "100%",
    marginTop: theme.spacing.unit * 3,
    overflowX: "auto"
  },
  table: {
    minWidth: 700
  },
  expand: {
    transform: "rotate(0deg)",
    transition: theme.transitions.create("transform", {
      duration: theme.transitions.duration.shortest
    }),
    marginLeft: "auto",
    [theme.breakpoints.up("sm")]: {
      marginRight: -8
    }
  },
  expandOpen: {
    transform: "rotate(180deg)"
  }
});

const grouped = values => {
  let finalArray = [];
  values.customers.filter(orders => {
    return Array.prototype.push.apply(finalArray, orders);
  });

  return finalArray;
};

const TableGroup = ({ classes, routes, ...other }) => {
  const [expanded, setExpanded] = useState({});

  const handleExpandClick = value => {
    setExpanded(expanded => {
      return {
        ...expanded,
        [value]: expanded[value] ? false : true
      };
    });
  };

  return routes.map((route, routeIndex) => {
    return (
      <TableRow>
        <TableCell colspan="5">
          <CardActions disableActionSpacing>
            <b>
              {route.name} - ({grouped(route).length}){" "}
            </b>
            <IconButton
              className={
                expanded[route.name] ? classes.expandOpen : classes.expand
              }
              onClick={() => handleExpandClick(route.name)}
              aria-expanded={route.name}
              aria-label="Show more"
            >
              <ExpandMoreIcon />
            </IconButton>
          </CardActions>
          <Collapse in={expanded[route.name]} timeout="auto" unmountOnExit>
            <Table {...other}>
              <TableBody>
                {grouped(route).map(row => {
                  return (
                    <TableRow key={row.id}>
                      <TableCell text>{row.reference}</TableCell>
                      <TableCell text>{row.customer.full_name}</TableCell>
                      <TableCell numeric>{row.total}</TableCell>
                      <TableCell>{row.status}</TableCell>
                      <TableCell>{row.created_at}</TableCell>
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          </Collapse>
        </TableCell>
      </TableRow>
    );
  });
};

const SimpleTable = ({ classes }) => {
  const [routes, setRoutes] = useState([]);
  const [loading, setLoading] = useState(true);

  const fetchAllOrders = async () => {
    const result = await getOrdersBasedOnRouteQuery();
    if (!result.loading) {
      setRoutes(result.data.route);
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchAllOrders();
  }, [loading === true]);

  if (loading) {
    return <div>Loading...</div>;
  }

  return (
    <Paper className={classes.root}>
      <Table>
        <TableHead>
          <TableRow>
            <TableCell>Reference</TableCell>
            <TableCell numeric>Customer Name</TableCell>
            <TableCell numeric>Total</TableCell>
            <TableCell numeric>Status</TableCell>
            <TableCell numeric>Created At</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          <TableGroup classes={classes} routes={routes} groupProperty="name" />
        </TableBody>
      </Table>
    </Paper>
  );
};

SimpleTable.propTypes = {
  classes: PropTypes.object.isRequired
};

export default withStyles(styles)(SimpleTable);

Upvotes: 0

bluehipy
bluehipy

Reputation: 2294

An approach for Material Ui , but can be used with same structure in other table formats:

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
import Collapse from '@material-ui/core/Collapse';
import CardActions from '@material-ui/core/CardActions';
import IconButton from '@material-ui/core/IconButton';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';

const styles = theme => ({
  root: {
    width: '100%',
    marginTop: theme.spacing.unit * 3,
    overflowX: 'auto',
  },
  table: {
    minWidth: 700,
  },
  expand: {
    transform: 'rotate(0deg)',
    transition: theme.transitions.create('transform', {
      duration: theme.transitions.duration.shortest,
    }),
    marginLeft: 'auto',
    [theme.breakpoints.up('sm')]: {
      marginRight: -8,
    },
  },
  expandOpen: {
    transform: 'rotate(180deg)',
  },
});

let id = 0;
function createData(name, calories, fat, carbs, protein) {
  id += 1;
  return { id, name, calories, fat, carbs, protein };
}

const rows = [
  createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
  createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
  createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
  createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
  createData('Eclair', 262, 16.0, 24, 6.0),
  createData('Eclair', 262, 16.0, 24, 6.0),
  createData('Cupcake', 305, 3.7, 67, 4.3),
  createData('Cupcake', 305, 3.7, 67, 4.3),
  createData('Gingerbread', 356, 16.0, 49, 3.9),
  createData('Gingerbread', 356, 16.0, 49, 3.9)
];
class TableGroup extends React.Component {
  constructor(props) {
    super(props);
    this.state = { expanded: {} };
  }
  handleExpandClick(key) {
    let state = { ...this.state };
    state.expanded[key] = !!!state.expanded[key];
    this.setState(state);
  }
  render() {
    const props = this.props;
    const { groupProperty, rows, ...other } = props;
    const groups = rows.reduce((acc, row) => {
      acc[row[groupProperty]] = acc[row[groupProperty]] || [];
      acc[row[groupProperty]].push(row);
      return acc;
    }, {});
    const keys = Object.keys(groups);


    return keys.map(key => (
      <TableRow>
        <TableCell colspan="5">
          <CardActions disableActionSpacing>
            <b>{key} ({groups[key].length})</b>
            <IconButton
              className={this.state.expanded[key] ? props.classes.expandOpen : props.classes.expand}
              onClick={this.handleExpandClick.bind(this, key)}
              aria-expanded={this.state.expanded[key]}
              aria-label="Show more"
            >
              <ExpandMoreIcon />
            </IconButton>
          </CardActions>
          <Collapse in={this.state.expanded[key]} timeout="auto" unmountOnExit>
            <Table {...other}>
              <TableBody>
                {groups[key].map(row => (
                  <TableRow key={row.id}>
                    <TableCell component="th" scope="row">
                      {row.name}
                    </TableCell>
                    <TableCell numeric>{row.calories}</TableCell>
                    <TableCell numeric>{row.fat}</TableCell>
                    <TableCell numeric>{row.carbs}</TableCell>
                    <TableCell numeric>{row.protein}</TableCell>
                  </TableRow>
                )
                )}
              </TableBody>
            </Table>
          </Collapse>
        </TableCell>
      </TableRow>
    )
    )
  }
};

function SimpleTable(props) {
  const { classes } = props;

  return (
    <Paper className={classes.root}>
      <Table >
        <TableHead>
          <TableRow>
            <TableCell>Dessert (100g serving)</TableCell>
            <TableCell numeric>Calories</TableCell>
            <TableCell numeric>Fat (g)</TableCell>
            <TableCell numeric>Carbs (g)</TableCell>
            <TableCell numeric>Protein (g)</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          <TableGroup classes={classes} rows={rows} groupProperty="name" />
        </TableBody>
      </Table>
    </Paper>
  );
}

SimpleTable.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(SimpleTable);

Upvotes: 1

Doa
Doa

Reputation: 503

The Table component doesn't currently support expansion, but you can hack around that using the expandable card component, just make sure you adjust the vertical alignment of the row.

Here's a code snippet:

<TableBody displayRowCheckbox={false}>
  {this.props.user.leads.map((lead, i) => (
    <TableRow key={i}>
      <TableRowColumn>
        <Card style={{boxShadow: 'none'}}>
          <CardHeader
            title={lead.brand}
            style={{paddingLeft: 0, fontWeight: 600}}
            actAsExpander={true}
          />
          <CardText expandable={true}>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
            Donec mattis pretium massa. Aliquam erat volutpat. Nulla facilisi.
            Donec vulputate interdum sollicitudin. Nunc lacinia auctor quam sed pellentesque.
            Aliquam dui mauris, mattis quis lacus id, pellentesque lobortis odio.
          </CardText>
        </Card>
      </TableRowColumn>
      <TableRowColumn style={{verticalAlign: 'top', height: 'auto', paddingTop: '1.4em'}}>{lead.budget}</TableRowColumn>
      <TableRowColumn style={{verticalAlign: 'top', height: 'auto', paddingTop: '1.4em'}}>{lead.eventName ? 'Event' : 'Content'}</TableRowColumn>
      <TableRowColumn style={{verticalAlign: 'top', height: 'auto', paddingTop: '1.4em'}}>{lead.firstName + ' ' + lead.lastName}</TableRowColumn>
      <TableRowColumn style={{verticalAlign: 'top', height: 'auto', paddingTop: '1.4em'}}>Archive | Start Campaign</TableRowColumn>
    </TableRow>
  ))}
</TableBody>

Upvotes: 2

Related Questions