gregnb / mui-datatables

Datatables for React using Material-UI
MIT License
2.7k stars 931 forks source link

Is there any simple way to group rows? #904

Open sarawinter opened 5 years ago

sarawinter commented 5 years ago

I am wondering if there is any easy way to group rows by a common field/column value, such as a date field?

gabrielliwerant commented 5 years ago

It depends on what you mean by "group." Column headers allow sorting, and you can define a custom sort which will group along any column values you want.

sarawinter commented 5 years ago

I am looking for something like this... screen Where the columns are grouped by the CustomerPo field.

The way that I have it working now is that I have a mui-datatable with all of the rows expanded and a custom component in renderExpandableRow.

This has required me to do some tweaking. I keep the data that belongs to the expanded row in a column with the display: 'excluded' option so that I can send it on to the expanded child component.

The trouble I am facing now is that the columns in the mui-datatable really should be reflecting the data in the child components, which I have managed to do, however, the view columns and the filtering don't really work "out of the box".

Here is a bunch of code that might help...

My data structure looks like this (simplified):

const data = [{
   CustomerPo: "1",
   DocumentHeader: "abcdef",
   children: [{
      CustomerPo: "1"
      CreatedDate: "2019-08-08",
      },{
      CustomerPo: "1"
      CreatedDate: "2019-08-09",
   },{
   CustomerPo: "2",
   DocumentHeader: "gheij",
   children: [{
      CustomerPo: "2"
      CreatedDate: "2019-08-08",
      },{
      CustomerPo: "2"
      CreatedDate: "2019-08-09",
   }]
}];

My mui-datatable looks like this (simplified):

class GroupedOrders extends React.Component {

    dosomething = (column, action) => {
        columnViewOptions[column] = action === "add" ? true : false;
    }

    render() {
        const columns = [
            {
                name: "DocumentHeader", // header
                label: 'Some header',
                options: {
                    display: true,
                    filter: false,
                    sort: true,
                    viewColumns: false
                }
            },
            {
                name: "OrderLines", // for order lines...
                options: {
                    display: 'excluded',
                    filter: false
                }
            },
            {
                name: "CreatedDate",
                label: 'Created',
                options: {
                    display: columnViewOptions.CreatedDate,
                    sort: false,
                    viewColumns: true
                }
            },
            {
                name: "CustomerPo",
                label: 'Customer Po',
                options: {
                    display: true,
                    filter: false,
                    sort: false
                }
            },
        ];

        const data = formattedOuterData();
        const expandedRows = data.map((v, i) => i);

        const columnViewOptions = {
            CreatedDate: true,
            CustomerPo: true,
        };

        const options = {
            filter: true,
            filterType: "dropdown",
            responsive: "scroll",
            print: false,
            download: false,
            selectableRows: 'none',
            expandableRows: true,
            rowsExpanded: expandedRows,
            renderExpandableRow: (rowData, rowMeta) => {
                return rowData[1].map((row, i) => <OrderLine data={row} key={`orderLine_${i}`} columnViewOptions={columnViewOptions} />);
            },
            onColumnViewChange: (column, action) => {
                this.dosomething(column, action);
            },
        };

        return (
            <MUIDataTable
                title={"NDH Orders"}
                data={data}
                options={options}
                columns={columns}
            />
        );
    }
}

The columnViewOptions allows me to keep track of which columns should be shown. This does not work completely though, because the child component seems to rerender before the change occurs so the columns are always diffing by one :(

My custom child component looks like this (simplified):

function OrderLine({ orderLine , columnViewOptions, restData }) {
    return (
        <TableRow>
            <TableCell>&nbsp;</TableCell>
            <TableCell>
                {orderLine.DocumentStatus}
            </TableCell>
            <TableCell>
                {orderLine.CreatedDate}
            </TableCell>
            {columnViewOptions.CustomerPo &&
                <TableCell>
                    {orderLine.CustomerPo}
                </TableCell>
            }
        </TableRow>
    );
}

Does this make any sense?

sarawinter commented 5 years ago

I only need the sorting on the first column, which is my parent's CustomerPo field. But I would like the filters and view columns to work.

gabrielliwerant commented 5 years ago

So, this library is not really built to handle nested data in the way you are attempting to handle it, so there's not going to be a good way to force it in and then rely on the other functions like filters, search, download, etc. We have to keep in mind that this library is built on top of the material Google recommendations for data tables, so I don't want to stray too far from that. Material specs have guidelines around the way that certain data is presented and your case is well outside of those specs, so it's a bit out of scope.

That being said, here are some suggestions for things you might try, albeit with different UX.

sarawinter commented 5 years ago

I actually solved this quite nicely without having to write any "hacky" code. :) I even got the column view and filters to work.

If you want an example I'd be happy to share :)

gabrielliwerant commented 5 years ago

Sure, feel free to open a PR with the example and I'll take a look!

L-U-C-K-Y commented 4 years ago

Hi @sarawinter

We would also like to implement a similar scenario, could I kindly ask you to share your solution?

Thanks! 😄

tolgacag commented 4 years ago

I actually solved this quite nicely without having to write any "hacky" code. :) I even got the column view and filters to work.

If you want an example I'd be happy to share :)

Hi @sarawinter , If you share your solution, we will be happy :)

fernandoofj commented 4 years ago

Hi @sarawinter. Can you share your solution with us?

mxmlnglt commented 4 years ago

any chance you can share your code @sarawinter ???

patorjk commented 4 years ago

This table should definitley support grouping natively. The solution @sarawinter describes is mostly a product of this table being so flexable. However, theoretically it should be pretty straight forward to add native support. A "grouping" option could be added, and if present, the table would transform the internal data structure in a way that's similar to how sara did her's. Then, the table could present an expand arrow that would render this data when expanded.

The only tricky parts would be handling filters (which may not be too bad), and handling nested data. I'm thinking the API could look like this for a simple case:

options = {
    grouping: "Some Header"
}

And this for a nested case:

options: {
    grouping: ["Some Header", "Another Header"],
}

Though I'll need to think about this some. This will probably be the next thing I tackle after the draggable columns PR is complete.

tigershen23 commented 4 years ago

@sarawinter any chance you can expand on your solution?

sarawinter commented 4 years ago

Hi, sorry, but I have left the project where I was working with this library. But I will see if I can make a mock version of the solution we used now that I have a little extra time.

tigershen23 commented 4 years ago

Thank you Sara! I've actually decided to go a separate direction for my project, but I'm sure the others in this thread would be thankful for that.

On Thu, Jul 16, 2020 at 12:27 AM, sarawinter < notifications@github.com > wrote:

Hi, sorry, but I have left the project where I was working with this library. But I will see if I can make a mock version of the solution we used now that I have a little extra time.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub ( https://github.com/gregnb/mui-datatables/issues/904#issuecomment-659214605 ) , or unsubscribe ( https://github.com/notifications/unsubscribe-auth/AA4DDINQRI2TVXM2F3MUFFLR32TXPANCNFSM4IUYVWYA ).

patorjk commented 4 years ago

Beta version of a grouping feature has been submitted as a PR here: https://github.com/gregnb/mui-datatables/pull/1441