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

[DataGrid] Allow to control the columns visibility #3554

Merged
merged 37 commits into from Jan 19, 2022

Conversation

flaviendelangle
Copy link
Member

@flaviendelangle flaviendelangle commented Jan 5, 2022

Closes #2198
Closes #1412
Part of #3448

Goals

  • Allow to control the visible columns just like the other models visibleColumnsModel + onVisibleColumnsModelChange

  • Do not break existing code with GridColDef.hide even for users switching manually the visibility with apiRef.current.updateColumns (add a temporary sync from the columns to the model)

Advancement

  • Add visibleColumnsModel and onVisibleColumnsModelChange
  • When visibleColumnsModel is not controlled, generate it from GridColDef.hide
  • Add visibleColumnsModel to the initialState prop (for [DataGrid] Add other sub-states to the initialState prop  #3448)
  • Deprecate onColumnVisibilityChange and only use it when the update comes from GridColDef.hide
  • Deprecate GridColDef.hide
  • Document
  • Add tests for controlled / initialState behavior
  • Duplicate all tests using GridColDef.hide to also test with the model

Release note

  • 🙈 Allow to control the columns visibility ([DataGrid] Allow to control the columns visibility #3554) @flaviendelangle

    // To fully control
    <DataGrid
      columnVisibilityModel={columnVisibilityModel}
      onColumnVisilibilityModelChange={newModel => setColumnVisibilityModel(newModel)}
    />
    
    // To initialize without controlling
    <DataGrid
      initialState={{
        columns: {
          columnVisibilityModel
        }
      }}
    />

    See the documentation for more details.

    The hide property from GridColDef still works but has been deprecated.

@flaviendelangle flaviendelangle self-assigned this Jan 5, 2022
@flaviendelangle flaviendelangle added the component: data grid This is the name of the generic UI component, not the React module! label Jan 5, 2022
@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Jan 7, 2022
@github-actions
Copy link

github-actions bot commented Jan 7, 2022

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@flaviendelangle flaviendelangle marked this pull request as draft January 7, 2022 12:37
@flaviendelangle flaviendelangle added the new feature New feature or request label Jan 7, 2022
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Jan 7, 2022
@flaviendelangle flaviendelangle marked this pull request as ready for review January 10, 2022 08:06
@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Jan 10, 2022
@github-actions
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Jan 10, 2022
Copy link
Member

@m4theushw m4theushw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if by allowing the visible columns to be controlled it won't conflict with other features in the future. I remember that with editRowsModel it caused a lot of problems, since we lost the warranty that the value would be updated synchronously. Now we may need to wait for the next render.

Should visibleColumnsModel receive an object where each key value is true (visible) or false (hidden)? It could be renamed to columnVisibilityModel in this case. With an array, it becomes a pain to hide a specific column. Also, the object doesn't require all fields to be present. Users might be upset when we drop hide and require them to pass all the visible fields.

I noticed a bug if I have checkboxSelection={false} then I change it to checkboxSelection={true}. The checkbox column is never visible nor onVisibleColumnsModelChange is called. See this CodeSandbox.

docs/src/pages/components/data-grid/columns/columns.md Outdated Show resolved Hide resolved
it('should update `visibleColumnsModel` but not `GridColDef.hide` in state', () => {
render(<TestDataGridPro initialState={{ columns: { visibleColumnsModel: ['id'] } }} />);
apiRef.current.setColumnVisibility('id', false);
expect(apiRef.current.state.columns.lookup.id.hide).to.equal(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't be making assertions on the state, they may change while yielding the same result for the user.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can listen to columnChange events to get the same result if we really want to avoid state assertions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also check if columnVisibilityChange was not called. My point is that we don't recommend direct state access, but to use selectors or API methods instead. That way, the test should ensure that if someone access the state via one of the recommended ways it will return the correct value. We shouldn't be testing the internal implementation, but what is one the public API or can be seen (UI).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I'll use the selector.
It won't impact the end user but users that use the selectors could have problems if we update the hide field by mistake.

@@ -147,9 +147,9 @@ describe('<DataGrid /> - Layout & Warnings', () => {

it('should support columns.valueGetter using `getValue` (deprecated)', () => {
const columns = [
{ field: 'id', hide: true },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this test be reverted to ensure that the old API still works?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As valueGetter is deprecated, I chose to switch this test to the new behavior without keeping the old one.

But I could duplicate it and test both valueGetter + hide and valueGetter + columnVisibilityModel.

@flaviendelangle
Copy link
Member Author

flaviendelangle commented Jan 12, 2022

I'm not sure if by allowing the visible columns to be controlled it won't conflict with other features in the future. I remember that with editRowsModel it caused a lot of problems, since we lost the warranty that the value would be updated synchronously. Now we may need to wait for the next render.

I feel like this one is closer to the other model we already have like selectionModel or filterModel.
A method call or the UI try to update the model => The user can update to controlled prop if he wants => The UI react to the prop model update.
I agree that the question is worth asking though.

Should visibleColumnsModel receive an object where each key value is true (visible) or false (hidden)? It could be renamed to columnVisibilityModel in this case. With an array, it becomes a pain to hide a specific column. Also, the object doesn't require all fields to be present. Users might be upset when we drop hide and require them to pass all the visible fields.

It is one of the main point I would like to discuss yes.
I did an array to follow the selectionModel format, but the more I think about it, the more I like the object, because we can treat the missing columns in the model as visible by default.

@m4theushw
Copy link
Member

m4theushw commented Jan 12, 2022

A method call or the UI try to update the model => The user can update to controlled prop if he wants => The UI react to the prop model update.

Yeah, once method or UI try to update the model we stop any further action. The side effects should be handled inside an effect to avoid the problems of editRowsModel with singleSelect.

I did an array to follow the selectionModel format, but the more I think about it, the more I like the object, because we can treat the missing columns in the model as visible by default.

I'm in favor of using an object to ease the transition for users. Internally, the array is converted to an object, so there's one step we can remove here. In the case of selectionModel doesn't make sense to explicitly define that a row is not selected, so an array is used.

@github-actions
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Jan 18, 2022
docs/src/pages/components/data-grid/columns/columns.md Outdated Show resolved Hide resolved
docs/src/pages/components/data-grid/columns/columns.md Outdated Show resolved Hide resolved
packages/grid/_modules_/grid/models/events/gridEvents.ts Outdated Show resolved Hide resolved
packages/grid/_modules_/grid/models/events/gridEvents.ts Outdated Show resolved Hide resolved
useGridStateInit(apiRef, (state) => {
const columnsState = createColumnsState({
apiRef,
columnsTypes,
columnsToUpsert: props.columns,
shouldRegenColumnVisibilityModelFromColumns: !shouldUseVisibleColumnModel,
currentColumnVisibilityModel:
props.columnVisibilityModel ?? props.initialState?.columns?.columnVisibilityModel ?? {},
Copy link
Member

@m4theushw m4theushw Jan 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default, the id column in the Commodity dataset is hidden. However, in https://deploy-preview-3554--material-ui-x.netlify.app/components/data-grid/columns/#column-visibility, all demos that use this dataset and have an initial state or the columnVisibilityModel prop, the id column is visible. With that being said, should the initial state be created also from the columns with hide? In controlled mode I guess there's nothing we can do, unless include the id column in the object.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should hide manually the id column on the demo I think.
I would advise against using the hide field when the model is defined. The way I built it, the hide field is deprecated. If we use the model, it is not taken into account at all.
That way it is not breaking, but users won't be able to do dirty tricks with both the hide and models.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the brokerId column is also hidden in the dataset. This makes me think if wouldn't be better to include a default initialState={{ columns: { columnVisibilityModel: { id: false } } }} below. Once we drop hide it will break all demos.

https://github.com/mui-org/material-ui-x/blob/f581ac12a3dfc9097f3877b3334a935b5fdbfdac/packages/grid/x-data-grid-generator/src/services/tree-data-generator.ts#L109

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Demo will have to manually pass it to the initialState when they override it
But yes better do it now, we will forget if we don't

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it planned to remove the shouldUseVisibleColumnModel in v6?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in v6 we would always use the model, the hide field would not exist anymore.

flaviendelangle and others added 4 commits January 18, 2022 16:03
Co-authored-by: Matheus Wichman <matheushw@outlook.com>
Co-authored-by: Matheus Wichman <matheushw@outlook.com>
Co-authored-by: Matheus Wichman <matheushw@outlook.com>
Co-authored-by: Matheus Wichman <matheushw@outlook.com>
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Jan 18, 2022
@flaviendelangle
Copy link
Member Author

flaviendelangle commented Jan 18, 2022

I have 2 Argos diff, I will try to fix them tomorrow

docs/src/pages/components/data-grid/columns/columns.md Outdated Show resolved Hide resolved
docs/src/pages/components/data-grid/columns/columns.md Outdated Show resolved Hide resolved
docs/src/pages/components/data-grid/columns/columns.md Outdated Show resolved Hide resolved
useGridStateInit(apiRef, (state) => {
const columnsState = createColumnsState({
apiRef,
columnsTypes,
columnsToUpsert: props.columns,
shouldRegenColumnVisibilityModelFromColumns: !shouldUseVisibleColumnModel,
currentColumnVisibilityModel:
props.columnVisibilityModel ?? props.initialState?.columns?.columnVisibilityModel ?? {},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it planned to remove the shouldUseVisibleColumnModel in v6?

@flaviendelangle flaviendelangle merged commit b8c1f08 into mui:master Jan 19, 2022
@flaviendelangle flaviendelangle deleted the columns-visibility branch January 19, 2022 16:23
@flaviendelangle flaviendelangle changed the title [DataGrid] Add controlled behavior for the visible columns [DataGrid] Allow to control the columns visibility Jan 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: data grid This is the name of the generic UI component, not the React module! new feature New feature or request
Projects
None yet
4 participants