Search code examples
reactjsmaterial-uimaterial-table

Prevent row fields from resetting on custom validation


I'm making my own validation in material-table when adding a new row, so it avoids creating a new one with any missing fields. The thing is I'm trying to prevent the creation but I want the row not to close, instead keeping it in it's editable state, with the data the user wrote, so it's not lost. I kinda resolved keeping the row editable, but when it validated the fields, all the data the user entered resets.

import React, { Component } from "react";
import { checkObjectLength, checkObjectKey } from "./../helpers";
import MaterialTable from "material-table";
import SnackbarNotification from "./SnackbarNotification";

class CustomTable extends Component {
  state = {
    open: false,
    message: "",
    alertStyle: "",
    temporaryData: {},
    columns: [
      {
        title: "Column1",
        field: "column1",
        lookup: {
          1: "option1",
          2: "option2",
          3: "option3"
        }
      },
      {
        title: "Column2",
        field: "column2",
        lookup: {
          10: "option1",
          11: "option2",
          12: "option3",
          13: "option4"
        }
      },
      {
        title: "column3",
        field: "column3",
        lookup: {
          20: "option1"
        }
      },
      { title: "column4", field: "column4" }
    ],
    data: [
      {
        column1: "somedata",
        column2: "somedata",
        column3: "somedata",
        column4: "somedata"
      }
    ]
  };

  handleClose = () => {
    this.setState({
      open: false
    });
  };

  render() {
    return (
      <div>
        <style global="true" jsx="true">
          {`
            .MuiFormControl-root.MuiTextField-root {
              width: 100%;
            }
          `}
        </style>

        <CustomTable
          options={{
            search: false,
            actionsColumnIndex: 4,
            filtering: true
          }}
          components={{
            Container: props => props.children
          }}
          title="Search by"
          columns={this.state.columns}
          data={this.state.data}
          editable={{
            onRowAdd: newData => {
              return new Promise(resolve => {
                setTimeout(() => {
                  const data = [...this.state.data];
                  if (checkObjectLength(newData)) {
                    return this.setState({
                      open: true,
                      message: "Some fields are missing!",
                      alertStyle: "error",
                      temporaryData: newData
                    });
                  }
                  resolve();
                  data.push(newData);
                  this.setState({
                    ...this.state,
                    data,
                    open: true,
                    message: "Successfully saved!",
                    alertStyle: "success"
                  });
                }, 300);
              });
            },
            onRowUpdate: (newData, oldData) => {
              return new Promise(resolve => {
                setTimeout(() => {
                  resolve();
                  const data = [...this.state.data];
                  //Only checking this field since it's the only one that can be empty on edit
                  if (checkObjectKey(newData.value)) {
                    return this.setState({
                      open: true,
                      message: "Some fields are missing!",
                      alertStyle: "error"
                    });
                  }
                  data[data.indexOf(oldData)] = newData;
                  this.setState({
                    ...this.state,
                    data,
                    open: true,
                    message: "Successfully updated!",
                    alertStyle: "success"
                  });
                }, 300);
              });
            },
            onRowDelete: oldData => {
              return new Promise(resolve => {
                setTimeout(() => {
                  resolve();
                  const data = [...this.state.data];
                  data.splice(data.indexOf(oldData), 1);
                  this.setState({
                    ...this.state,
                    data,
                    open: true,
                    message: "Successfully deleted!",
                    alertStyle: "success"
                  });
                }, 300);
              });
            }
          }}
        />
        <SnackbarNotification
          open={this.state.open}
          handleClose={this.handleClose}
          message={this.state.message}
          alertStyle={this.state.alertStyle}
        />
      </div>
    );
  }
}

export default CustomTable;


Solution

  • use reject to keep them remain in editable state

    onRowUpdate: (newData, oldData) => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          const data = [...this.state.data];
          //Only checking this field since it's the only one that can be empty on edit
          if (checkObjectKey(newData.value)) {
            return reject(); // Reject when invalid
          }
          resolve(); // Move resolve below here
          data[data.indexOf(oldData)] = newData;
          this.setState({
            ...this.state,
            data,
            open: true,
            message: "Successfully updated!",
            alertStyle: "success"
          });
        }, 300);
      });
    },