Search code examples
reactjsreact-hooksmaterial-table

React MaterialTable editable row validation - how to show and hide error?


I have a material-table and I want to run field validations on row editing only when the user clicks in save button.

I have this function to set the error:

const [nameError, setNameError] = useState({
        error: false,
        label: '',
        helperText: '',
    });

And the onRowUpdate:

onRowUpdate: (newData, oldData) =>
                    new Promise((resolve, reject) => {
                        setTimeout(() => {

                            if (newData.name === '') {
                                setNameError({
                                    error: true,
                                    label: 'required',
                                    helperText: 'Required helper text'
                                });
                                reject();
                                return;
                            }

                            resolve();
                            if (oldData) {
                                setState(prevState => {
                                    const data = [...prevState.data];
                                    data[data.indexOf(oldData)] = newData;
                                    return { ...prevState, data };
                                });
                            }
                        }, 600);
                    })

I can set the error, the problem is if I click on cancel button, next time I click on edit the error continues visible.

Here is a gif:

enter image description here

I tried to look for an event something like onCancelEdit but I didn't find anything, do you know how to solve this?

You can try this in Edit MaterialTableDemo - validation error

Complete React component code:

const tableIcons = {
    Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
    Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
    Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
    Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
    DetailPanel: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
    Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
    Export: forwardRef((props, ref) => <SaveAlt {...props} ref={ref} />),
    Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
    FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
    LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
    NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
    PreviousPage: forwardRef((props, ref) => <ChevronLeft {...props} ref={ref} />),
    ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
    Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
    SortArrow: forwardRef((props, ref) => <ArrowDownward {...props} ref={ref} />),
    ThirdStateCheck: forwardRef((props, ref) => <Remove {...props} ref={ref} />),
    ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />)
};



export default function MaterialTableDemo() {

    const [nameError, setNameError] = useState({
        error: false,
        label: '',
        helperText: '',
    });



    const [state, setState] = React.useState({
        data: [
            {
                name: 'Mehmet',
                surname: 'Baran'
            },
            {
                name: 'Zerya Betül',
                surname: 'Baran'
            },
        ],
    });

    return (
        <MaterialTable
            title="Editable Example"
            columns={
                [
                    {
                        title: 'Name', field: 'name',
                        editComponent: (props) => (
                            <TextField
                                type="text"
                                error={nameError.error}
                                helperText={nameError.helperText}
                                value={props.value ? props.value : ''}
                                onChange={e => props.onChange(e.target.value)}
                            />
                        )
                    },
                    { title: 'Surname', field: 'surname' }
                ]}
            data={state.data}
            icons={tableIcons}
            editable={{
                onRowUpdate: (newData, oldData) =>
                    new Promise((resolve, reject) => {
                        setTimeout(() => {

                            if (newData.name === '') {
                                setNameError({
                                    error: true,
                                    label: 'required',
                                    helperText: 'Required helper text'
                                });
                                reject();
                                return;
                            }

                            resolve();
                            if (oldData) {
                                setState(prevState => {
                                    const data = [...prevState.data];
                                    data[data.indexOf(oldData)] = newData;
                                    return { ...prevState, data };
                                });
                            }
                        }, 600);
                    })
            }}
        />
    );
}


Solution

  • Check if the value exists in editComponent.

    const [nameError, setNameError] = useState({
        error: false,
        label: "",
        helperText: "",
        validateInput: false
    });
    
    columns={[
      {
        title: "Name",
        field: "name",
        editComponent: props => (
        <TextField
            type="text"
            error={
            !props.value && nameError.validateInput
                ? nameError.error
                : false
            }
            helperText={
            !props.value && nameError.validateInput
                ? nameError.helperText
                : ""
            }
            value={props.value ? props.value : ""}
            onChange={e => {
            if (nameError.validateInput) {
                setNameError({
                ...nameError,
                validateInput: false
                });
            }
    
            props.onChange(e.target.value);
            }}
        />
        )
      },
      { title: "Surname", field: "surname" }
    ]}
    

    codesandbox