material-table-core / core

Datatable for React based on material-ui's table with additional features. Support us at https://opencollective.com/material-table-core
https://material-table-core.github.io
MIT License
296 stars 146 forks source link

Columns aren't sortable if they use `render` instead of `field` #826

Closed mateenkasim closed 9 months ago

mateenkasim commented 10 months ago

Describe the bug

If a column definition uses render instead of field to populate the cell, the resulting column won't sort when you click the column header.

To Reproduce

Compare this starter template: https://codesandbox.io/s/material-table-starter-template-forked-jlrfld to this fork: https://codesandbox.io/p/sandbox/material-table-starter-template-forked-kn7pdp

The only change I made was changing the "Word" column definition from { title: "Word", field: "word" } to { title: "Word", render: (o) => o.word }

The "Word" column in the starter template is sortable, while it is not sortable in my fork.

Expected behavior

The column should sort using the returned value of the render function, with exactly the same behavior as if it were just given the field. Whatever the user visibly sees is what should be used to sort.

I know I can add a custom sort, but nearly all of the tables on my app use the render field, and it's a bit of a pain to add the custom sort for all my tables when all I need is the default sorting behavior

Screenshots

Using field:

image

Using render:

image

Desktop (please complete the following information):

Additional context

My app is on v5 of this package, but from the sandboxes, it looks like the same bug exists on v6. I'm willing to try fixing this myself and making a PR, but I want to check with the maintainers first on desired behavior.

Domino987 commented 9 months ago

That's not actually a bug, you are just using render in the most basic way. Render is actually done to show the user html. It's a Function that cannot be sorted by. So render can return anything also buttons boxes or divs. Those are of course not sortable, so that's why render does not make sense to sort after. It looks like you would need some kind of transform callback instead?

mateenkasim commented 9 months ago

Ah, I see, that's a good consideration I didn't think about – I'll remove the bug tag then.

And yeah, a callback would be a neat way to access default sort behavior. Or something like:

{
    title: "Word",
    render: (o) => <strong>o.word</strong>,
    sortValue: (o) => o.word,
}

Or if the default sort function was importable:

import { defaultSort } from '@material-table/core';

{
    title: "Word",
    render: (o) => <strong>o.word</strong>,
    customSort: (o1, o2, ...args) => {
        const v1 = o1.word;
        const v2 = o2.word;
        return defaultSort(v1, v2, ...args);
    }
}

All that said, I made this issue so I wouldn't need to individually make a change to every column definition in my codebase. Since the issue I raised is actually the correct behavior, I'll find another way to make it work internally.

Thanks for your help and input!

Edit: Looks like I can't edit labels after I make the issue oops, future readers just know that this is not a bug