Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make the edit-mode field type of one material-table column dependent upon the value of another column, without affecting other rows?

Summary

I need the input field that appears when the user is in edit mode to be different depending on the value of a different column for that row. E.g. if the user is in edit mode and Column X has value A, then Column Y should be a text entry field. If, however, Column X has value B, then Column Y should be a dropdown select list. Importantly, this must not affect any other rows (i.e. the fact that Column Y might be a text entry field for this row should not affect the input type on any other row).

Mockup

In case it wasn’t clear what I was asking for, here is a mockup that shows the functionality I’m after.

1. Target type is 'Group', so 'Target' field is numeric entry enter image description here

2. Target type is 'Address', so 'Target' field is a select list of strings. Notice that the other rows entries are unaffected (i.e. they are still numeric fields) enter image description here

More detail

I am creating a lighting control app, and am using material-table as the means through which users specify what actions a button can take (it could be a single action, in which case the table would be a single row, or many actions, in which case the table would be many rows). They can either control a single device, which is stored in a database and should be selectable from a dropdown list, or a group of devices, in which case they manually enter the number of the group they wish to control.

Code

This code forms the basis of the mockups (above):

import React from "react";
import MaterialTable from 'material-table';

const devices = ["Device A (Stairs)", "Device B (Hallway)"];

export default class ControlSpecificationTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      columns: [
        { title: 'Step', field: 'step' },
        { title: 'Target Type', field: 'target_type', lookup: { 0: 'Address', 1: 'Group' } },
        { title: 'Target', field: 'target', initialEditValue: '0', lookup: { 0: devices[0], 1: devices[1] }},
        // { title: 'Target', field: 'target', initialEditValue: '0', type:'numeric'},

        {
          title: 'Control Type',
          field: 'control_type',
          lookup: { 0: 'Button', 1: 'Slider', 2: 'Arrows' },
        },
        {
            title: 'Command type',
            field: 'command_type',
            lookup: { 0: 'Arc level', 1: 'Minimum', 2: 'Maximum' }
        }, 
        {
            title: 'Command Value',
            field: 'command_value',
        },
        {
            title: 'Time Until Next Command (seconds)',
            field: 'time_until_next_command',
        }
      ],
      data: [
        { step: '1', target_type: 1, target: 1, control_type: 0, command_type: 0, command_value: 23, time_until_next_command: 3 },
        { step: '2', target_type: 1, target: 15, control_type: 1, command_type: 1, command_value: "N/A", time_until_next_command: 1 },
        { step: '3', target_type: 1, target: 13, control_type: 1, command_type: 1, command_value: "N/A", time_until_next_command: 1 },

      ]
    }
  }

  render() {
    return (
    <>
        <MaterialTable
            title="Control Steps"
            columns={this.state.columns}
            data={this.state.data}
            editable={
                {
                onRowAdd: newData =>
                    new Promise((resolve, reject) => {
                        resolve();
                    }),
                onRowUpdate: (newData, oldData) => {
                    new Promise((resolve, reject) => {
                        resolve();
                    })
                    },
                onRowDelete: oldData => 
                    new Promise((resolve, reject) => {
                        resolve();
                    }),
                }
            }
        />
    </>
    )
  }
}
like image 874
daviegravee Avatar asked Nov 09 '19 05:11

daviegravee


1 Answers

You have to keep track of the currently selected target_type and override the editComponent of the columns to show either the drop down or the textField:

 editComponent: t =>
        this.currentEditingTarget === 0 ? (
          <Select
            value={t.value}
            onChange={e => {
              t.onChange(e.target.value);
              console.group(e.target.value);
              this.currentEditingTarget = e.target.value;
            }}
          >
            <MenuItem value={0}>{devices[0]}</MenuItem>
            <MenuItem value={1}>{devices[1]}</MenuItem>
          </Select>
        ) : (
          <TextField
            value={t.value}
            onChange={e => t.onChange(e.target.value)}
            type="numeric"
          />
        ),

Here's a working codesandbox.

like image 79
Domino987 Avatar answered Nov 15 '22 05:11

Domino987