2
votes

I'm using react-material-table. I'm trying to validate the row edit.

Everything works fine for "native" material column. But I had to use a custom editComponent for one column rendering an Autocomplete.

{
      title: "test",
      field: "foo",
      editComponent: (props) => {


        return (
          <div>
            <Autocomplete

              onChange={(e, v) => this.handleFooChange(props.rowData.id, v)}
              //onChange={(e,v) => props.onChange(v)}
              id="people-company"
              options={[{ id: 1, name: "bar" }, { id: 2, name: "foo" }]}
              getOptionLabel={option => option.name}

              value={props.rowData.foo}
              filterSelectedOptions
              renderInput={params => (
                <TextField
                  {...params}
                  variant="outlined"
                  label="company"
                  placeholder="company"
                  margin="normal"
                  fullWidth
                />
              )}
            />
          </div>
        );
      },

My MaterialTable define EditRow and EditField

    const FormikMTInput = props => {

  return (
    <Field name={props.columnDef.field}>
      {({ field, form, meta }) => {
        const { name } = field;
        const { errors, setFieldValue } = form;
        //console.log("ShowError", errors);
        const showError = !!getIn(errors, name);

        return (
          <div>
            <MTableEditField
              {...props}
              {...field}
              error={showError}
              onChange={newValue => setFieldValue(name, newValue)}
            />
            {errors[field.name] && (
              <div style={{ color: "#f44336" }}>{errors[field.name]}</div>
            )}
          </div>
        );
      }}
    </Field>
  );
};

const MuiTableEditRow = ({ onEditingApproved, ...props }) => {

  return(
  <Formik

    validate={values => {
      const errors = {};
      if (!values.name) {
        errors.name = "Required";
      }
      if (!values.foo) {
        errors.foo = "Required";
      }

      return errors;
    }}
    initialValues={props.data}
    onSubmit={values => {
      if (values) {
        if (values.name.length > 2 && values.foo)
          onEditingApproved(props.mode, values, props.data);
      }
    }}
    render={({ submitForm }) => (
      <MTableEditRow {...props} onEditingApproved={submitForm} />
    )}
  />
)};
  <MaterialTable
      title="Editable Preview"
      columns={this.state.columns}
      data={this.state.data}
      components={{
        EditRow: MuiTableEditRow,
        EditField: FormikMTInput
      }}
    />

FormikMTInput is well fired on "default" columns. It is not the case for the overwrited editComponent. How can I pass errors to this column?

Here the sandbox

1

1 Answers

1
votes

The problem is, that the current value differs from the rowData value. So change value={props.rowData.foo} to value={props.value} in the autocomplete, to get the correct value. Previously, the rowData never changed on edit because the row still had the data until you save it.

Additionally, you should pass the already transformed value to the onChange function and not the event like this: onChange={v => props.onChange(v.target.value)}.

if (!id || id === undefined) return; is equal to if (!id) return;because !id returns true for undefined.

Last but not least, you are mutating your state data in

var myData = this.state.data;
   myData.forEach(d => {
      if (d.id === id) {
      d.foo = v;
    }
  });

which is a no-go. Change it to:

handleFooChange(id, v) {
    if (!id) return;
    const myData = this.state.data.map(d => d.id === id ? {...d, foo: v} : d);
    this.setState({ data: myData });
}