Comments (20)
thank you so much. I gave it a quick try and it's doing what I'd like to achieve. I'll let the powers that be know about the caveat no. 3. Honestly I think it would be great to add to the recipies. I went looking outside of MUI for this behavior and I saw something sort of like this but they couldn't get it to work with as many states and so I had to open a ticket. This is beyond helpful. Thank you so much.
from mui-x.
I've prepared a demo implementation that saves the exported state on every state change to localStorage and reloads it on page reload.
Have a look at it: https://codesandbox.io/s/datagridpremium-basic-forked-5542fr?file=/src/App.tsx
Design details:
- The demo is designed keeping in mind the state has to be persisted locally, if you want to persist it for multiple people/sessions/devices you may need to replace localStorage with a database layer.
- Right now, it uses the
onStateChange
event handler which fires a lot of times based on different internal state changes, it may cause performance issues, especially if you decide to switch to API for storing the state, I'd recommend doing it in a more "controlled" way by limiting the state export to specific event handlers you are interested in, likeonFilterModelChange
for example. - It doesn't persist and recover everything, only those which are supported by
apiRef.current.exportState
and accepted byinitialState
prop.
Let me know if the demo helps you achieve your required use case.
Thanks
I think this use case (persist and recover state locally) could be a good candidate for a recipe and could be useful for certain desktop-oriented apps. @cherniavskii Do you think it's worth it to add to the Recipes umbrella issue?
from mui-x.
ahh ok great. thanks for everything this was a big help
from mui-x.
Hi @lisaWriteJava
I believe there's a mistake in the initial state merging:
initialState={{
- cachedInitialState,
+ ...cachedInitialState,
sorting: {
sortModel: sortModel
}
}}
Here's a fixed demo: https://codesandbox.io/s/datagridpremium-basic-forked-w25xxc?file=/src/CommonGrid.jsx
This is a great candidate for the recipe as it's a pretty common pattern 👍🏻
from mui-x.
if using multiple grids in the same app, give the local storage a unique name for each. Otherwise the properties will get mingled.
from mui-x.
there isn't anything that shows this being able to be automatic once the user sorts/filters, etc
Could you elaborate more a bit the requirement? You want to save a state snapshot on every sort or filter operation? Is the rationale to revert to the current state if the user reopens/refreshes the page?
I believe you can achieve that by:
- Listening to the variable specific changes you are interested in (for example
onFilterModelChange
,onSortModelChange
) - Updating the state snapshot when a change event fires, which you can store in
localStorage
,db
, etc. - Revert to the saved state using
initialState
orapiRef.current.restoreState
on page load (or whenever you want)
About supporting it out of the box:
I am not in favor of it:
- There could be tons of ways to manage the storage of exported state depending on user's needs
- This is a rarely used use-case and could easily be achieved by adding some custom code (as I mentioned above)
Let me know if the suggested method would work in your use-case.
Thanks
from mui-x.
So I was trying to figure out a way that if a user sorts the columns, and/or reorders the columns, or pagination we can save that state without the need to create that view. Also, I want the state to be maintained if the user clicks goes to another page or refreshes. Essentially I'd like to persist the state of the datagrid.
how can I do this.
from mui-x.
Just one question, if I have an initial state set for a grid ie sort order is it possible to have both with this scenario
from mui-x.
Just one question, if I have an initial state set for a grid ie sort order is it possible to have both with this scenario
Sure thing, feel free to update the initialState
populating logic as per your requirement!
from mui-x.
Just to confirm something like below is fine:
initialState={{
...cachedInitialState,
sorting: {
sortModel: sortModel
}
}}
from mui-x.
Just to confirm something like below is fine:
Sure, you can override the sortModel
if the intention is to never persist it and always use a specific initialValue
for it.
But if the intention is to do this only for the first time and let the user change the sortModel afterwards, you can return this as a default value from getStateSnapshotFromLocalStorage
method instead of {}
from mui-x.
Hello,
While your code standbox worked for me, When I incorporated it into my code the state didn't save.
I'm workign up the sandbox
from mui-x.
ok here's an example of the state not saving when implemented in my code
https://codesandbox.io/s/datagridpremium-basic-forked-pk9s6y
from mui-x.
The codesandbox link you shared appears to be broken, here's the error it's throwing
from mui-x.
This is the updated sandbox: https://codesandbox.io/s/datagridpremium-basic-forked-pk9s6y?file=/src/CommonGrid.jsx
saving the sandbox was a challenge just in case the first link above doesn't work I also forked it to save here https://codesandbox.io/s/datagridpremium-basic-forked-6zpflz
from mui-x.
Just in case there is an issue viewing the sand box @MBilalShafi here is the code:
import { Box } from "@mui/material";
import CircularProgress from "@mui/material/CircularProgress";
import {
DataGridPremium,
GridToolbarContainer,
GridToolbarColumnsButton,
GridToolbarFilterButton,
GridToolbarExport,
GridToolbarDensitySelector,
gridClasses,
useGridApiRef,
GRID_DETAIL_PANEL_TOGGLE_COL_DEF
} from "@mui/x-data-grid-premium";
import PropTypes from "prop-types";
import { alpha } from "@mui/material/styles";
import { styled } from "@mui/material/styles";
const ODD_OPACITY = 0.2;
//class actions
function saveStateSnapshotToLocalStorage(stateSnapshot) {
console.info(
"State update: Update the state snap in localStorage",
stateSnapshot
);
localStorage.setItem("dataGridState", JSON.stringify(stateSnapshot));
}
function getStateSnapshotFromLocalStorage() {
const stringifiedState = localStorage.getItem("dataGridState");
return new Promise((resolve) => {
if (!stringifiedState) {
return resolve({});
}
const stateSnapshot = JSON.parse(stringifiedState);
return resolve(stateSnapshot);
});
}
function CustomToolbar() {
return (
<GridToolbarContainer
sx={{
width: "100%",
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
}}
>
<GridToolbarColumnsButton
sx={{
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
}}
/>
<GridToolbarFilterButton
sx={{
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
}}
/>
<GridToolbarDensitySelector
sx={{
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
}}
/>
<GridToolbarExport
sx={{
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
}}
/>
</GridToolbarContainer>
);
}
const StyledGridOverlay = styled("div")(({ theme }) => ({
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
height: "100%",
"& .ant-empty-img-1": {
fill: "#262626"
},
"& .ant-empty-img-2": {
fill: "#595959"
},
"& .ant-empty-img-3": {
fill: "#434343"
},
"& .ant-empty-img-4": {
fill: "#1c1c1c"
},
"& .ant-empty-img-5": {
fillOpacity: "0.08",
fill: "#fff"
}
}));
function CustomNoRowsOverlay() {
return (
<StyledGridOverlay>
<svg
width="120"
height="100"
viewBox="0 0 184 152"
aria-hidden
focusable="false"
>
<g fill="none" fillRule="evenodd">
<g transform="translate(24 31.67)">
<ellipse
className="ant-empty-img-5"
cx="67.797"
cy="106.89"
rx="67.797"
ry="12.668"
/>
<path
className="ant-empty-img-1"
d="M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z"
/>
<path
className="ant-empty-img-2"
d="M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"
/>
<path
className="ant-empty-img-3"
d="M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z"
/>
</g>
<path
className="ant-empty-img-3"
d="M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z"
/>
<g className="ant-empty-img-4" transform="translate(149.65 15.383)">
<ellipse cx="20.654" cy="3.167" rx="2.849" ry="2.815" />
<path d="M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z" />
</g>
</g>
</svg>
<Box sx={{ mt: 1, fontSize: 16, fontWeight: "bolder" }}>No Data</Box>
</StyledGridOverlay>
);
}
const mockViolationColumns = [
{
id: "user",
headerName: "User",
field: "user",
type: "string",
flex: 1,
aggregable: false,
groupable: false,
headerAlign: "center",
valueGetter: (params) => {
// console.log('in value getting for User params: ', params)
//Asided from everything else, must set somethign in maybe name or a field to do the filter on
return params.value.name;
},
renderCell: (rowInfo) => {
// console.log('valueFormatter for User: ', rowInfo) //you need to verify values below
if (rowInfo.row.user.name) {
return <div> placeHolder </div>;
} else {
return <span>Missing Name Info 2</span>;
}
}
},
{
id: "violation_type",
headerName: "Violation Type",
field: "is_role",
flex: 1,
headerAlign: "center",
aggregable: false,
groupable: false,
//Change to value gettter
renderCell: (rowInfo) => {
return rowInfo.value;
},
valueGetter: (params) => {
// console.log('The violation type value getter ', params, ' \n params.row.is_role: ', params.row.is_role, ' trying value too: ', params.value)
if (params.row.is_role) {
return "Unqualified User (Role)";
} else {
return "Unassigned User (Accessor)";
}
}
},
{
field: "accessor_or_role",
headerName: "Accessor or Role",
flex: 1,
headerAlign: "center",
aggregable: false,
groupable: false,
//This allows for rendering a react component
renderCell: (rowInfo) => {
// console.log(' Ist accessor or role: ', rowInfo)
if (rowInfo.row.is_role) {
return <div> placeHolder </div>;
}
return <div> placeHolder </div>;
},
valueGetter: (params) => {
// console.log('The violation type value getter ', params, ' \n params.row.is_role: ', params.row.is_role, ' trying value too: ', params.value)
if (params.row.is_role) {
return params.row.role.name;
} else {
return params.row.accessor.name;
}
}
},
{
id: "detected_on",
headerName: "Detected On",
field: "created_date",
flex: 1,
type: "date",
headerAlign: "center",
aggregable: false,
groupable: false,
valueFormatter: (params) => {
//console.log('VF The created_date on params: ', params)
if (params.value == null) {
return "";
}
return params.value;
},
valueGetter: (params) => {
// console.log('VG the created_date in params: ', params)
if (params.row.created_date == null) {
return "";
}
// console.log('created_date The last modified from row: ', params.row.created_date)
const date = new Date(params.row.created_date);
// console.log('to return the created_date in getter: ', date)
return date;
}
},
{
id: "last_updated",
headerName: "Last Updated",
field: "last_modified",
flex: 1,
type: "date",
headerAlign: "center",
aggregable: false,
groupable: false,
valueFormatter: (params) => {
// console.log('VF The last_modified on params: ', params)
if (params.value == null) {
return "";
}
return params.value;
},
valueGetter: (params) => {
// console.log('VG the last_modified in params: ', params)
if (params.row.last_modified == null) {
return "";
}
//console.log('last_modified The last modified from row: ', params.row.last_modified)
const date = new Date(params.row.last_modified);
//console.log('to return the last_modified in getter: ', date)
return date;
}
},
{
headerName: "Suspension",
type: "string",
field: "rolesuspension",
flex: 1,
aggregable: false,
groupable: false,
headerAlign: "center",
renderCell: (rowInfo) => {
// console.log('Row info rolesuspension to view: ', rowInfo)
if (!rowInfo.row.is_role) {
return (
<span>
<i>N/A</i>
</span>
);
}
const roleSus = rowInfo.row.rolesuspension;
//console.log(rowInfo, ' = the rolesuspension ', roleSus)
if (!roleSus || roleSus.cleared_date) {
return <span>None</span>;
}
if (roleSus.suspension_activated_date) {
return (
<span>
<span
className="fa fa-minus-circle text-danger"
role="img"
aria-hidden={true}
/>{" "}
Suspended {roleSus.suspension_activated_date}
</span>
);
}
const daysRemaining = 4;
return (
<span>
<span
className="fa fa-hourglass-half"
role="img"
aria-hidden={true}
/>{" "}
{daysRemaining} day{daysRemaining != 1 && "s"} until suspension
</span>
);
},
valueGetter: (rowInfo) => {
// console.log('Row info rolesuspension: ', rowInfo)
if (!rowInfo.row.is_role) {
//may need to use the is_role property This needs to be checked HS and maybe a more examples ffor this poroperty
return "N/A";
}
const roleSus = rowInfo.value;
if (!roleSus || roleSus.cleared_date) {
return "None";
}
if (roleSus.suspension_activated_date) {
return "Suspended" + roleSus.suspension_activated_date;
}
const daysRemaining = 4;
let daysVerbiage = "";
if (daysRemaining > 1) {
daysVerbiage = daysRemaining + " days until suspension";
} else {
daysVerbiage = daysRemaining + " day until suspension";
}
return daysVerbiage;
}
},
{
...GRID_DETAIL_PANEL_TOGGLE_COL_DEF,
renderHeader: () => "+/-",
headerAlign: "center",
sortable: false,
filterable: false,
aggregable: false,
groupable: false,
valueGetter: (params) => {
// console.log('VG the GRID_DETAIL_PANEL_TOGGLE_COL_DEF in params: ', params)
// console.log('return the GRID_DETAIL_PANEL_TOGGLE_COL_DEF in params: ', params.row.id + "-" + params.row.name)
return params.row.id + "-" + params.row.url;
},
renderCell: (params) => {
// console.log('renderCell the GRID_DETAIL_PANEL_TOGGLE_COL_DEF in params: ', params)
return <div>test</div>;
}
}
];
const mockUserMembershipViolations = {
data: {
violations: [
{
id: 1,
uuid: "123",
user: {
sid: "1234",
name: "Apple Cider 2",
first_name: "Apple",
last_name: "Cider 2",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
adm_account: false,
role: {
name: "April is A ROLE",
description: "#f00",
url: "www.twitter.com",
uuid: "7890",
parent_object: null,
userCount: 4,
my_permissions: [
{
add_users: true,
create: true,
read: true,
update: true,
delete: true,
grant_user_suspensions: true,
set_rules: true
}
]
},
accessor: {
sid: "1234",
name: "An accessor Name",
first_name: " bfgr",
last_name: "fererer",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
is_role: true,
created_date: "2023-02-11T14:51:39Z",
cleared_date: "2023-06-11T14:51:39Z",
url: "www.fake.com",
last_modified: "2023-03-11T14:51:39Z",
rolesuspension: null
},
{
id: 2,
uuid: "123ab",
user: {
sid: "1234",
name: "Samy Zebra",
first_name: "Samy",
last_name: "Zebra",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
adm_account: false,
role: {
name: "April Role",
description: "#f00",
url: "www.twitter.com",
uuid: "7890",
parent_object: null,
userCount: 4,
my_permissions: [
{
add_users: true,
create: true,
read: true,
update: true,
delete: true,
grant_user_suspensions: true,
set_rules: true
}
]
},
accessor: {
sid: "1234",
name: "Not a Role Accessor Name BOO",
first_name: " bfgr",
last_name: "fererer",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
is_role: false,
created_date: "2023-01-11T14:51:39Z",
cleared_date: "2023-06-11T14:51:39Z",
url: "www.fake.com",
last_modified: "2023-05-11T14:51:39Z",
rolesuspension: null
}
],
users: [
{
sid: "1234",
name: "geger",
first_name: " bfgr",
last_name: "fererer",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
{
sid: "1tt234",
name: "2geger",
first_name: " bfgr",
last_name: "fererer",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
}
],
roles: [
{
name: "April",
description: "#f00",
url: "www.twitter.com",
uuid: "7890",
parent_object: null,
userCount: 4,
my_permissions: [
{
add_users: true,
create: true,
read: true,
update: true,
delete: true,
grant_user_suspensions: true,
set_rules: true
}
]
}
],
accessors: [
{
sid: "1234",
name: "geger",
first_name: " bfgr",
last_name: "fererer",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "accessor",
entity_types: []
}
]
},
isFetching: false,
fetched: false,
hasError: true,
errorObj: {}
};
const CommonGrid = ({ ...other }) => {
const apiRef = useGridApiRef();
const [cachedInitialState, setCachedInitialState] = React.useState();
const [sortModel, setSortModel] = React.useState([
{
field: "user",
sort: "desc"
},
{ field: "detected_on", desc: "desc" }
]);
React.useEffect(() => {
const getSnapshot = async () => {
const snapshotFromLocalStorage = await getStateSnapshotFromLocalStorage();
console.log(
"Page Mount: Recovered state from localStorage",
snapshotFromLocalStorage
);
setCachedInitialState(snapshotFromLocalStorage);
};
getSnapshot();
}, []);
const saveSnapshot = React.useCallback(() => {
const stateSnapshot = apiRef.current.exportState();
saveStateSnapshotToLocalStorage(stateSnapshot);
}, [apiRef]);
if (!cachedInitialState) {
return <CircularProgress />;
}
return (
<Box
sx={{
height: "100%",
width: "100%",
"& .datagridHeader": {
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
},
"& .MuiDataGrid-footerContainer": {
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
},
"& .MuiTablePagination-root": {
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
},
"& .MuiTablePagination-displayedRows": {
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
},
"& .MuiSelect-standard": {
fontSize: "13px !important",
fontWeight: "bolder",
color: "#fff !important"
},
"& .MuiTablePagination-actions": {
fontSize: 13,
fontWeight: "bolder",
color: "#fff !important",
"& .MuiButtonBase-root": {
color: "#fff !important",
fontSize: 13
}
},
"& .MuiTablePagination-selectLabel": {
fontSize: 13,
fontWeight: "bolder",
color: "#fff !important"
},
"& .MuiTablePagination-selectIcon": {
fontSize: "13px !important",
fontWeight: "bolder",
color: "#fff !important"
},
"& .MuiTablePagination-selectRoot": {
fontSize: "13px !important",
fontWeight: "bolder",
color: "#fff !important"
},
"& .MuiTablePagination-input": {
fontSize: "13px !important",
fontWeight: "bolder",
color: "#fff !important"
},
"& .MuiDataGrid-columnHeader": {
backgroundColor: "#4d7496",
color: "#fff",
fontSize: 13,
fontWeight: 700
},
"& .MuiDataGrid-columnHeaderCheckbox": {
backgroundColor: "#4d7496",
color: "#fff",
fontSize: 13,
fontWeight: 700
},
"& .MuiDataGrid-cell": {
border: "1px solid rgb(224, 224, 224)",
fontSize: 13
},
"& .MuiDataGrid-root .MuiDataGrid-cell": {
whiteSpace: "normal !important",
wordWwrap: "break-word !important",
textAlign: "left"
},
"& .MuiDataGrid-sortIcon": {
backgroundColor: "#4d7496",
color: "#fff",
fontSize: 13,
fontWeight: 700,
opacity: "inherit !important"
},
"& .MuiDataGrid-filterIcon": {
backgroundColor: "#4d7496",
color: "#fff",
fontSize: 13,
fontWeight: 700,
opacity: "inherit !important"
},
"& .MuiDataGrid-columnHeaderTitle": {
fontWeight: "bolder"
}
}}
>
{"Tes"}
<br />
<br />
<DataGridPremium
apiRef={apiRef}
onStateChange={saveSnapshot}
rows={[
{
id: 1,
uuid: "123",
user: {
sid: "1234",
name: "Apple Cider 2",
first_name: "Apple",
last_name: "Cider 2",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
adm_account: false,
role: {
name: "April is A ROLE",
description: "#f00",
url: "www.twitter.com",
uuid: "7890",
parent_object: null,
userCount: 4,
my_permissions: [
{
add_users: true,
create: true,
read: true,
update: true,
delete: true,
grant_user_suspensions: true,
set_rules: true
}
]
},
accessor: {
sid: "1234",
name: "An accessor Name",
first_name: " bfgr",
last_name: "fererer",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
is_role: true,
created_date: "2023-02-11T14:51:39Z",
cleared_date: "2023-06-11T14:51:39Z",
url: "www.fake.com",
last_modified: "2023-03-11T14:51:39Z",
rolesuspension: null
},
{
id: 2,
uuid: "123ab",
user: {
sid: "1234",
name: "Samy Zebra",
first_name: "Samy",
last_name: "Zebra",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
adm_account: false,
role: {
name: "April Role",
description: "#f00",
url: "www.twitter.com",
uuid: "7890",
parent_object: null,
userCount: 4,
my_permissions: [
{
add_users: true,
create: true,
read: true,
update: true,
delete: true,
grant_user_suspensions: true,
set_rules: true
}
]
},
accessor: {
sid: "1234",
name: "Not a Role Accessor Name BOO",
first_name: " bfgr",
last_name: "fererer",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
is_role: false,
created_date: "2023-01-11T14:51:39Z",
cleared_date: "2023-06-11T14:51:39Z",
url: "www.fake.com",
last_modified: "2023-05-11T14:51:39Z",
rolesuspension: null
}
]}
columns={mockViolationColumns}
sx={{
width: "100% !important",
".MuiDataGrid-iconButtonContainer": {
visibility: "visible"
},
".MuiDataGrid-sortIcon": {
opacity: "inherit !important"
},
".MuiTouchRipple-root": {
opacity: "inherit !important",
visibility: "visible !important"
},
".MuiDataGrid-menuIconButton": {
color: "#fff"
},
".MuiDataGrid-columnHeaderTitleContainerContent .MuiCheckbox-root": {
color: "#ffff !important",
fontSize: 14,
fontWeight: "bolder"
},
"& .MuiDataGrid-virtualScroller::-webkit-scrollbar": {
width: "0.4em"
},
"& .MuiDataGrid-virtualScroller::-webkit-scrollbar-track": {
color: "#4d7496"
},
"& .MuiDataGrid-virtualScroller::-webkit-scrollbar-thumb": {
backgroundColor: "#4d7496",
color: "#fff"
},
"& .MuiDataGrid-virtualScroller::-webkit-scrollbar-thumb:hover": {
backgroundColor: "#4d7496",
color: "#fff"
},
"& .MuiDataGrid-iconButtonContainer": {
marginLeft: "25px",
visibility: "visible !important",
width: "auto !important"
},
"& .MuiDataGrid-cell--withRenderer": {
fontSize: "13px !important"
},
"& .MuiDataGrid-menuIcon": {
fontSize: 14,
visibility: "visible !important",
width: "auto !important",
fontWeight: "bolder",
"& .MuiSvgIcon-root": {
fontSize: 14,
visibility: "visible !important",
width: "auto !important",
fontWeight: "bolder"
}
}
}}
getDetailPanelContent={other.getDetailPanelContent}
getDetailPanelHeight={() => "auto"}
rowThreshold={other.rowThreshold}
keepColumnPositionIfDraggedOutside={true}
loading={false}
paginationMode={"client"}
slots={{
noRowsOverlay: CustomNoRowsOverlay,
toolbar: CustomToolbar
}}
checkboxSelection
experimentalFeatures={{
ariaV7: true,
newEditingApi: true
}}
getRowClassName={(params) =>
params.indexRelativeToCurrentPage % 2 === 0 ? "even" : "odd"
}
initialState={{
cachedInitialState,
sorting: {
sortModel: sortModel
}
}}
sortingOrder={["desc", "asc"]}
sortModel={sortModel}
onSortModelChange={(model) => {
// console.log('****************** The column sort order chagnes \n\n\n\n')
setSortModel(model); //set the state
}}
pagination
/>
</Box>
);
};
/* CommonGrid.propTypes = {
columns: PropTypes.array,
rows: PropTypes.array,
tableTitle: PropTypes.string
}; */
export default CommonGrid;
from mui-x.
Hello @romgrk , please let me know what you need from me. I gave the code block above just in case the sandbox didn't load properly to show the issue.
from mui-x.
Thank you. I'll give this a try
Yes I agree it's a good candidate.
from mui-x.
Ok @cherniavskii I gave it a try. Your sandbox worked perfectly but when I integrated it into our code base the state still wouldn't save. I've forked the sandbox to show how a reload isn't working using my code https://codesandbox.io/s/datagridpremium-basic-forked-khqvcm?file=/src/CommonGrid.jsx
just in case the sandbox has issues like it did in the past below is the code
import React from "react";
import { Box } from '@mui/material';
import CircularProgress from "@mui/material/CircularProgress";
import {
DataGridPremium,
GridToolbarContainer,
GridToolbarColumnsButton,
GridToolbarFilterButton,
GridToolbarExport,
GridToolbarDensitySelector,
gridClasses,
useGridApiRef,
} from '@mui/x-data-grid-premium';
import PropTypes from "prop-types";
import { alpha } from "@mui/material/styles";
import { styled } from "@mui/material/styles";
const ODD_OPACITY = 0.2;
//class actions
function saveStateSnapshotToLocalStorage(stateSnapshot) {
console.info(
"State update: Update the state snap in localStorage",
stateSnapshot
);
localStorage.setItem("dataGridState", JSON.stringify(stateSnapshot));
}
function getStateSnapshotFromLocalStorage() {
const stringifiedState = localStorage.getItem("dataGridState");
return new Promise((resolve) => {
if (!stringifiedState) {
return resolve({});
}
const stateSnapshot = JSON.parse(stringifiedState);
return resolve(stateSnapshot);
});
}
const StripedDataGrid = styled(DataGridPremium)(({ theme }) => ({
[`& .${gridClasses.row}.even`]: {
backgroundColor: theme.palette.grey[200],
"&:hover, &.Mui-hovered": {
backgroundColor: alpha(theme.palette.primary.main, ODD_OPACITY),
"@media (hover: none)": {
backgroundColor: "transparent"
}
},
"&.Mui-selected": {
backgroundColor: alpha(
theme.palette.primary.main,
ODD_OPACITY + theme.palette.action.selectedOpacity
),
"&:hover, &.Mui-hovered": {
backgroundColor: alpha(
theme.palette.primary.main,
ODD_OPACITY +
theme.palette.action.selectedOpacity +
theme.palette.action.hoverOpacity
),
// Reset on touch devices, it doesn't add specificity
"@media (hover: none)": {
backgroundColor: alpha(
theme.palette.primary.main,
ODD_OPACITY + theme.palette.action.selectedOpacity
)
}
}
}
}
}));
const StyledGridOverlay = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
height: '100%',
'& .ant-empty-img-1': {
fill: theme.palette.mode === 'light' ? '#aeb8c2' : '#262626',
},
'& .ant-empty-img-2': {
fill: theme.palette.mode === 'light' ? '#f5f5f7' : '#595959',
},
'& .ant-empty-img-3': {
fill: theme.palette.mode === 'light' ? '#dce0e6' : '#434343',
},
'& .ant-empty-img-4': {
fill: theme.palette.mode === 'light' ? '#fff' : '#1c1c1c',
},
'& .ant-empty-img-5': {
fillOpacity: theme.palette.mode === 'light' ? '0.8' : '0.08',
fill: theme.palette.mode === 'light' ? '#f5f5f5' : '#fff',
},
}));
function CustomNoRowsOverlay() {
return (
<StyledGridOverlay>
<svg
width="120"
height="100"
viewBox="0 0 184 152"
aria-hidden
focusable="false"
>
<g fill="none" fillRule="evenodd">
<g transform="translate(24 31.67)">
<ellipse
className="ant-empty-img-5"
cx="67.797"
cy="106.89"
rx="67.797"
ry="12.668"
/>
<path
className="ant-empty-img-1"
d="M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z"
/>
<path
className="ant-empty-img-2"
d="M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"
/>
<path
className="ant-empty-img-3"
d="M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z"
/>
</g>
<path
className="ant-empty-img-3"
d="M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z"
/>
<g className="ant-empty-img-4" transform="translate(149.65 15.383)">
<ellipse cx="20.654" cy="3.167" rx="2.849" ry="2.815" />
<path d="M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z" />
</g>
</g>
</svg>
<Box sx={{ mt: 1, fontSize: 16, fontWeight: 'bolder' }}>No Data</Box>
</StyledGridOverlay>
);
}
const CommonGrid = ({ /*columns, rows, tableTitle, sortingOrder, sortModel, onSortModelChange, */
actionButton, handleSelectedItems, ...other }) => {
const apiRef = useGridApiRef();
const [cachedInitialState, setCachedInitialState] = React.useState();
const [rowSelectionModel, setRowSelectionModel] = React.useState([]);
const [checkboxSelection, setCheckboxSelection] = React.useState(true);
const [sortModel, setSortModel] = React.useState([
{
field: "user",
sort: "desc"
},
{ field: "detected_on", desc: "desc" }
]);
React.useEffect(() => {
const getSnapshot = async () => {
const snapshotFromLocalStorage = await getStateSnapshotFromLocalStorage();
console.log(
"Page Mount: Recovered state from localStorage",
snapshotFromLocalStorage
);
setCachedInitialState(snapshotFromLocalStorage);
};
getSnapshot();
}, []);
const saveSnapshot = React.useCallback(() => {
const stateSnapshot = apiRef.current.exportState();
saveStateSnapshotToLocalStorage(stateSnapshot);
}, [apiRef]);
if (!cachedInitialState) {
return <CircularProgress />;
}
function CustomToolbar() {
return (
<GridToolbarContainer sx={{
width: "100%",
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
}} >
<GridToolbarColumnsButton sx={{
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
}} />
<GridToolbarFilterButton sx={{
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
}} />
<GridToolbarDensitySelector sx={{
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
}} />
<GridToolbarExport sx={{
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
}} />
{actionButton ? actionButton : null}
</GridToolbarContainer>
);
}
return (
<Box
sx={{
height: "100%",
width: "100%",
"& .datagridHeader": {
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
},
"& .MuiDataGrid-footerContainer": {
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
},
"& .MuiTablePagination-root": {
backgroundColor: "#4d7496",
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder"
},
"& .MuiTablePagination-displayedRows": {
color: "#fff !important",
fontSize: 13,
fontWeight: "bolder",
},
"& .MuiSelect-standard": {
fontSize: "13px !important",
fontWeight: "bolder",
color: "#fff !important",
},
"& .MuiTablePagination-actions": {
fontSize: 13,
fontWeight: "bolder",
color: "#fff !important",
"& .MuiButtonBase-root": {
color: "#fff !important",
fontSize: 13,
},
},
"& .MuiTablePagination-selectLabel": {
fontSize: 13,
fontWeight: "bolder",
color: "#fff !important",
},
"& .MuiTablePagination-selectIcon": {
fontSize: "13px !important",
fontWeight: "bolder",
color: "#fff !important",
},
"& .MuiTablePagination-selectRoot": {
fontSize: "13px !important",
fontWeight: "bolder",
color: "#fff !important",
},
"& .MuiTablePagination-input": {
fontSize: "13px !important",
fontWeight: "bolder",
color: "#fff !important",
},
"& .MuiDataGrid-columnHeader": {
backgroundColor: "#4d7496",
color: "#fff",
fontSize: 13,
fontWeight: 700
},
"& .MuiDataGrid-columnHeaderCheckbox": {
backgroundColor: "#4d7496",
color: "#fff",
fontSize: 13,
fontWeight: 700
},
"& .MuiDataGrid-cell": {
border: "1px solid rgb(224, 224, 224)",
fontSize: 13
},
"& .MuiDataGrid-root .MuiDataGrid-cell": {
whiteSpace: "normal !important",
wordWwrap: "break-word !important",
textAlign: 'left'
},
"& .MuiDataGrid-sortIcon": {
backgroundColor: "#4d7496",
color: "#fff",
fontSize: 13,
fontWeight: 700,
opacity: "inherit !important"
},
"& .MuiDataGrid-filterIcon": {
backgroundColor: "#4d7496",
color: "#fff",
fontSize: 13,
fontWeight: 700,
opacity: "inherit !important"
},
"& .MuiDataGrid-columnHeaderTitle": {
fontWeight: 'bolder'
}
}} >
{/* {tableTitle} */}TESTING saving state
<br />
<br />
<StripedDataGrid
apiRef={apiRef}
onStateChange={saveSnapshot}
columns={[
{
id: "user",
headerName: "User",
field: "user",
type: "string",
flex: 1,
aggregable: false,
groupable: false,
headerAlign: "center",
valueGetter: (params) => {
// console.log('in value getting for User params: ', params)
//Asided from everything else, must set somethign in maybe name or a field to do the filter on
return params.value.name;
},
renderCell: (rowInfo) => {
// console.log('valueFormatter for User: ', rowInfo) //you need to verify values below
if (rowInfo.row.user.name) {
return <div> placeHolder </div>;
} else {
return <span>Missing Name Info 2</span>;
}
}
},
{
id: "violation_type",
headerName: "Violation Type",
field: "is_role",
flex: 1,
headerAlign: "center",
aggregable: false,
groupable: false,
//Change to value gettter
renderCell: (rowInfo) => {
return rowInfo.value;
},
valueGetter: (params) => {
// console.log('The violation type value getter ', params, ' \n params.row.is_role: ', params.row.is_role, ' trying value too: ', params.value)
if (params.row.is_role) {
return "Unqualified User (Role)";
} else {
return "Unassigned User (Accessor)";
}
}
},
{
field: "accessor_or_role",
headerName: "Accessor or Role",
flex: 1,
headerAlign: "center",
aggregable: false,
groupable: false,
//This allows for rendering a react component
renderCell: (rowInfo) => {
// console.log(' Ist accessor or role: ', rowInfo)
if (rowInfo.row.is_role) {
return <div> placeHolder </div>;
}
return <div> placeHolder </div>;
},
valueGetter: (params) => {
// console.log('The violation type value getter ', params, ' \n params.row.is_role: ', params.row.is_role, ' trying value too: ', params.value)
if (params.row.is_role) {
return params.row.role.name;
} else {
return params.row.accessor.name;
}
}
},
{
id: "detected_on",
headerName: "Detected On",
field: "created_date",
flex: 1,
type: "date",
headerAlign: "center",
aggregable: false,
groupable: false,
valueFormatter: (params) => {
//console.log('VF The created_date on params: ', params)
if (params.value == null) {
return "";
}
return params.value;
},
valueGetter: (params) => {
// console.log('VG the created_date in params: ', params)
if (params.row.created_date == null) {
return "";
}
// console.log('created_date The last modified from row: ', params.row.created_date)
const date = new Date(params.row.created_date);
// console.log('to return the created_date in getter: ', date)
return date;
}
},
{
id: "last_updated",
headerName: "Last Updated",
field: "last_modified",
flex: 1,
type: "date",
headerAlign: "center",
aggregable: false,
groupable: false,
valueFormatter: (params) => {
// console.log('VF The last_modified on params: ', params)
if (params.value == null) {
return "";
}
return params.value;
},
valueGetter: (params) => {
// console.log('VG the last_modified in params: ', params)
if (params.row.last_modified == null) {
return "";
}
//console.log('last_modified The last modified from row: ', params.row.last_modified)
const date = new Date(params.row.last_modified);
//console.log('to return the last_modified in getter: ', date)
return date;
}
},
{
headerName: "Suspension",
type: "string",
field: "rolesuspension",
flex: 1,
aggregable: false,
groupable: false,
headerAlign: "center",
renderCell: (rowInfo) => {
// console.log('Row info rolesuspension to view: ', rowInfo)
if (!rowInfo.row.is_role) {
return (
<span>
<i>N/A</i>
</span>
);
}
const roleSus = rowInfo.row.rolesuspension;
//console.log(rowInfo, ' = the rolesuspension ', roleSus)
if (!roleSus || roleSus.cleared_date) {
return <span>None</span>;
}
if (roleSus.suspension_activated_date) {
return (
<span>
<span
className="fa fa-minus-circle text-danger"
role="img"
aria-hidden={true}
/>{" "}
Suspended {roleSus.suspension_activated_date}
</span>
);
}
const daysRemaining = 4;
return (
<span>
<span
className="fa fa-hourglass-half"
role="img"
aria-hidden={true}
/>{" "}
{daysRemaining} day{daysRemaining != 1 && "s"} until suspension
</span>
);
},
valueGetter: (rowInfo) => {
// console.log('Row info rolesuspension: ', rowInfo)
if (!rowInfo.row.is_role) {
//may need to use the is_role property This needs to be checked HS and maybe a more examples ffor this poroperty
return "N/A";
}
const roleSus = rowInfo.value;
if (!roleSus || roleSus.cleared_date) {
return "None";
}
if (roleSus.suspension_activated_date) {
return "Suspended" + roleSus.suspension_activated_date;
}
const daysRemaining = 4;
let daysVerbiage = "";
if (daysRemaining > 1) {
daysVerbiage = daysRemaining + " days until suspension";
} else {
daysVerbiage = daysRemaining + " day until suspension";
}
return daysVerbiage;
}
},
]}
rows={[
{
id: 1,
uuid: "123",
user: {
sid: "1234",
name: "Apple Cider 2",
first_name: "Apple",
last_name: "Cider 2",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
adm_account: false,
role: {
name: "April is A ROLE",
description: "#f00",
url: "www.twitter.com",
uuid: "7890",
parent_object: null,
userCount: 4,
my_permissions: [
{
add_users: true,
create: true,
read: true,
update: true,
delete: true,
grant_user_suspensions: true,
set_rules: true
}
]
},
accessor: {
sid: "1234",
name: "An accessor Name",
first_name: " bfgr",
last_name: "fererer",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
is_role: true,
created_date: "2023-02-11T14:51:39Z",
cleared_date: "2023-06-11T14:51:39Z",
url: "www.fake.com",
last_modified: "2023-03-11T14:51:39Z",
rolesuspension: null
},
{
id: 2,
uuid: "123ab",
user: {
sid: "1234",
name: "Samy Zebra",
first_name: "Samy",
last_name: "Zebra",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
adm_account: false,
role: {
name: "April Role",
description: "#f00",
url: "www.twitter.com",
uuid: "7890",
parent_object: null,
userCount: 4,
my_permissions: [
{
add_users: true,
create: true,
read: true,
update: true,
delete: true,
grant_user_suspensions: true,
set_rules: true
}
]
},
accessor: {
sid: "1234",
name: "Not a Role Accessor Name BOO",
first_name: " bfgr",
last_name: "fererer",
email: "fererer",
is_active: true,
user_type: "user",
duty_org: "NSA",
org: "trrere",
has_adm_account: true,
url: "www.google.com",
uuid: "fferer",
my_permissions: {
create: true,
update: true,
destroy: true,
write: true,
read: true
},
objectType: "user",
entity_types: []
},
is_role: false,
created_date: "2023-01-11T14:51:39Z",
cleared_date: "2023-06-11T14:51:39Z",
url: "www.fake.com",
last_modified: "2023-05-11T14:51:39Z",
rolesuspension: null
}
]}
sx={{
width: '100% !important',
".MuiDataGrid-iconButtonContainer": {
visibility: "visible"
},
".MuiDataGrid-sortIcon": {
opacity: "inherit !important"
},
".MuiTouchRipple-root": {
opacity: "inherit !important",
visibility: "visible !important"
},
".MuiDataGrid-menuIconButton": {
color: "#fff"
},
".MuiDataGrid-columnHeaderTitleContainerContent .MuiCheckbox-root": {
color: '#ffff !important',
fontSize: 14,
fontWeight: 'bolder'
},
'& .MuiDataGrid-virtualScroller::-webkit-scrollbar': {
width: '0.4em',
},
'& .MuiDataGrid-virtualScroller::-webkit-scrollbar-track': {
color: '#4d7496',
},
'& .MuiDataGrid-virtualScroller::-webkit-scrollbar-thumb': {
backgroundColor: '#4d7496',
color: '#fff'
},
'& .MuiDataGrid-virtualScroller::-webkit-scrollbar-thumb:hover': {
backgroundColor: '#4d7496',
color: '#fff'
},
'& .MuiDataGrid-iconButtonContainer': {
marginLeft: '25px',
visibility: 'visible !important',
width: 'auto !important',
},
"& .MuiDataGrid-cell--withRenderer": {
fontSize: "13px !important"
},
"& .MuiDataGrid-menuIcon": {
fontSize: 14,
visibility: 'visible !important',
width: 'auto !important',
fontWeight: 'bolder',
"& .MuiSvgIcon-root": {
fontSize: 14,
visibility: 'visible !important',
width: 'auto !important',
fontWeight: 'bolder',
}
},
}}
getDetailPanelContent={other.getDetailPanelContent}
getDetailPanelHeight={() => 'auto'}
rowThreshold={other.rowThreshold}
keepColumnPositionIfDraggedOutside={true}
loading={false}
paginationMode={"client"}
slots={{
noRowsOverlay: CustomNoRowsOverlay,
toolbar: CustomToolbar,
}}
checkboxSelection
experimentalFeatures={{
ariaV7: true,
newEditingApi: true
}}
getRowClassName={(params) =>
params.indexRelativeToCurrentPage % 2 === 0 ? "even" : "odd"
}
initialState={{
...cachedInitialState,
sorting: {
sortModel: sortModel
}
}}
sortingOrder={["desc", "asc"]}
sortModel={sortModel}
onSortModelChange={(model) => {
// console.log('****************** The column sort order chagnes \n\n\n\n')
setSortModel(model); //set the state
}}
pagination
/>
</Box>
);
};
/* CommonGrid.propTypes = {
columns: PropTypes.array,
rows: PropTypes.array,
tableTitle: PropTypes.string
}; */
export default CommonGrid;
from mui-x.
So after fooling with this a bit more I got it working. Not sure why the example didn't work but after playing in the my code the state was saved and retrieved as expected.
from mui-x.
Related Issues (20)
- [data grid] Scroll on GridNoRowsOverlay when unstable_headerFilters is true
- [data grid] Unable to Paste Row Data in Data Grid with CAPS Lock Key Enabled HOT 5
- [data grid] `upsertFilterItems` removes filters that are not part of the update HOT 7
- [data grid] Double initialization (performance issue) HOT 5
- [docs] Demo ComponentExplorerNoSnap crashes HOT 2
- [data grid] Starting row editing using the API doesn't trigger "onRowEditStart" event HOT 3
- [pickers] DateTimePicker: Unable to override default placeholder MM/DD/YYYY hh:mm aa HOT 9
- [data grid] dateTime column how to show date/time for another timezone HOT 3
- [data grid] Row Grouping mixed with non grouped rows HOT 3
- [data grid] Include columnType in GridFilterItem HOT 3
- [DateRangePicker] Add shortcut info in Date Range Picker to the field HOT 9
- [DateCalendar] error when trying to use DateCalendar HOT 1
- [data grid] DataGrid does not respect custom GridActionsCellItem HOT 1
- [charts] `LineChart` color improvement HOT 4
- [data grid] Styling for clickable row HOT 1
- [data grid] Date Filter Issue with "before" Operator in @mui/x-data-grid-premium v6.0.0+ HOT 1
- [pickers] clearable for DateTimePicker HOT 3
- DataGridPremium's column auto size property doesn't work without using setTimeout function HOT 2
- [DateTimeRangePicker] Fix OK button behavior
- [DateTimeRangePicker] Improve examples design and default widths
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from mui-x.