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

Validate the mui data grid cell and show red border #14976

Closed
achoud444 opened this issue Oct 15, 2024 · 1 comment
Closed

Validate the mui data grid cell and show red border #14976

achoud444 opened this issue Oct 15, 2024 · 1 comment
Labels
bug 🐛 Something doesn't work component: data grid This is the name of the generic UI component, not the React module!

Comments

@achoud444
Copy link

achoud444 commented Oct 15, 2024

Steps to reproduce

Link to live example: (required)

Steps:
1.
2.
3.

Current behavior

I'm using the DataGrid and want to prevent the user from proceeding before validation.
Currently, I am using preProcessEditCellProps, but it only triggers validation when the cell is focused. I need it to also trigger validation when the save button is clicked

Expected behavior

What I want is on clicking on save button If a cell is empty or incorrectly filled, it should display a red border to indicate the error.

import React, { useState } from 'react';
import {
  DataGridPremium,
  GridColDef,
  GridRowId,
  useGridApiRef,
  GridActionsCellItem,
  GridRowModes,
  GridRowModesModel,
} from '@mui/x-data-grid-premium';
import { Button, Select, MenuItem, FormControl, InputLabel, IconButton, Snackbar } from '@mui/material';
import SaveIcon from '@mui/icons-material/Save';
import CancelIcon from '@mui/icons-material/Cancel';

interface RowData {
  id: number;
  name: string;
  country: string;
  age: number;
  vat: number;
}

const countryData = {
  USA: { vat: 0 },
  France: { vat: 20 },
  Germany: { vat: 19 },
  Spain: { vat: 21 },
  Brazil: { vat: 17 },
};

const initialRows: RowData[] = [
  { id: 1, name: 'John Doe', country: 'USA', age: 30, vat: countryData['USA'].vat },
  { id: 2, name: 'Jane Smith', country: 'France', age: 25, vat: countryData['France'].vat },
];

const DataGridExample: React.FC = () => {
  const [rows, setRows] = useState<RowData[]>(initialRows);
  const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
  const [snackbar, setSnackbar] = useState<{ children: string; severity: 'success' | 'error' | 'info' } | null>(null);
  const apiRef = useGridApiRef();

  const handleSaveClick = async (id: GridRowId) => {
    // Save the changes and exit edit mode
    setRowModesModel((prev) => ({
      ...prev,
      [id]: { mode: GridRowModes.View },
    }));
  };

  const handleCancelClick = (id: GridRowId) => {
    apiRef.current.setRowMode(id, 'view');
    setRowModesModel((prev) => ({
      ...prev,
      [id]: { mode: GridRowModes.View },
    }));
  };

  const handleEditClick = (id: GridRowId) => {
    const isAnyRowInEditMode = Object.keys(rowModesModel).some(
      (rowId) => rowModesModel[rowId] ?.mode === GridRowModes.Edit
    );

    if (isAnyRowInEditMode) {
      setSnackbar({
        children: 'Please save or cancel the current edit before modifying another row.',
        severity: 'info',
      });
      return;
    }

    setRowModesModel({
      ...Object.keys(rowModesModel).reduce((acc, key) => {
        acc[key] = { mode: GridRowModes.View };
        return acc;
      }, {} as GridRowModesModel),
      [id]: { mode: GridRowModes.Edit, fieldToFocus: 'vat' }, // Focus on 'vat' field
    });
  };

  const handleDeleteClick = (id: GridRowId) => {
    setRows((prevRows) => prevRows.filter((row) => row.id !== id));
  };

  const columns: GridColDef[] = [
    { field: 'name', headerName: 'Name', width: 150, editable: true },
    {
      field: 'country',
      headerName: 'Country',
      width: 150,
      editable: true,
      renderEditCell: (params) => (
        <FormControl fullWidth>
          <InputLabel>Country</InputLabel>
          <Select
            value={params.value}
            native
            onChange={(event) => {
              apiRef.current.setEditCellValue({
                id: params.id,
                field: 'country',
                value: event.target.value,
              });
              apiRef.current.setEditCellValue({
                id: params.id,
                field: 'vat',
                value: countryData[event.target.value].vat,
              });
            }}
          ><option key={''} value={''}>
              Select
										</option>
            {Object.keys(countryData).map((country) => (
              <option key={country} value={country}>
                {country}
              </option>
            ))}
          </Select>
        </FormControl>
      ),
    },
    { field: 'age', headerName: 'Age', width: 100, editable: true },
    { field: 'vat', headerName: 'VAT (%)', width: 100 },
    {
      field: 'actions',
      headerName: 'Actions',
      width: 150,
      renderCell: (params) => {
        const isInEditMode = rowModesModel[params.id] ?.mode === GridRowModes.Edit;
        return isInEditMode ? (
          <>
            <IconButton onClick={() => handleSaveClick(params.id)}>
              <SaveIcon />
            </IconButton>
            <IconButton onClick={() => handleCancelClick(params.id)}>
              <CancelIcon />
            </IconButton>
          </>
        ) : (
            <>
              <Button onClick={() => handleEditClick(params.id)}>Edit</Button>
              <Button onClick={() => handleDeleteClick(params.id)}>Delete</Button>
            </>
          );
      },
    },
  ];

  return (
    <div style={{ height: 400, width: '100%' }}>
      <DataGridPremium
        apiRef={apiRef}
        rows={rows}
        columns={columns}
        pageSize={5}
        editMode="row"
        getRowId={(row) => row.id}
        rowModesModel={rowModesModel}
        onRowModesModelChange={(newModel) => setRowModesModel(newModel)}
      />
      {snackbar && (
        <Snackbar
          open={!!snackbar}
          onClose={() => setSnackbar(null)}
          autoHideDuration={3000}
          message={snackbar.children}
          severity={snackbar.severity}
        />
      )}
    </div>
  );
};

export default DataGridExample;

Context

No response

Your environment

npx @mui/envinfo
  Don't forget to mention which browser you used.
  Output from `npx @mui/envinfo` goes here.

Search keywords: Validate the mui data grid cell and show red border

@achoud444 achoud444 added bug 🐛 Something doesn't work status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Oct 15, 2024
@github-actions github-actions bot added the component: data grid This is the name of the generic UI component, not the React module! label Oct 15, 2024
@github-actions github-actions bot removed the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Oct 17, 2024
Copy link

This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue.
Now, if you have additional information related to this issue or things that could help future readers, feel free to leave a comment.

Note

@achoud444 How did we do? Your experience with our support team matters to us. If you have a moment, please share your thoughts in this short Support Satisfaction survey.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: data grid This is the name of the generic UI component, not the React module!
Projects
None yet
Development

No branches or pull requests

1 participant