Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there any simple way to group rows? #904

Open
sarawinter opened this issue Sep 9, 2019 · 15 comments
Open

Is there any simple way to group rows? #904

sarawinter opened this issue Sep 9, 2019 · 15 comments

Comments

@sarawinter
Copy link

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

@gabrielliwerant
Copy link
Collaborator

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
Copy link
Author

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
Copy link
Author

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
Copy link
Collaborator

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.

  • Pre-sort your data according to how you want it displayed, and use custom styling to alternate row coloring to make it clear where the groups are.
  • Use multiple tables, one for each group of data.
  • Consider a different UI visual abstraction aside from data tables. Maybe collapsible lists would be more appropriate for your use case.

@gabrielliwerant gabrielliwerant added the wontfix Support for this request is not planned at this time label Sep 10, 2019
@sarawinter
Copy link
Author

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
Copy link
Collaborator

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

@L-U-C-K-Y
Copy link

Hi @sarawinter

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

Thanks! 😄

@tolgacag
Copy link

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
Copy link

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

@mxmlnglt
Copy link
Contributor

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

@patorjk patorjk added enhancement investigate further and removed wontfix Support for this request is not planned at this time labels Jun 15, 2020
@patorjk
Copy link
Collaborator

patorjk commented Jun 15, 2020

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.

@patorjk patorjk pinned this issue Jun 15, 2020
@patorjk patorjk removed the question label Jun 15, 2020
@patorjk patorjk unpinned this issue Jun 18, 2020
@tigershen23
Copy link

@sarawinter any chance you can expand on your solution?

@sarawinter
Copy link
Author

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
Copy link

tigershen23 commented Jul 16, 2020 via email

@patorjk
Copy link
Collaborator

patorjk commented Jul 26, 2020

Beta version of a grouping feature has been submitted as a PR here: #1441

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants