0

I am using the material-table package to display nested data tables (two levels of nesting) in a React app. Here is a simplified version of my nested table to provide context:

Nested Material Table Layout

My database query returns the nested rows as JSON on each record. I pass the nested JSON object to the detailPanel, where I render another <MaterialTable> to display this data. Importantly, the nested data does not have the same column structure as the top-level data, so the parentChildData Tree Data functionality isn't an option for me (if I'm mistaken, please show me how that would work for my case).

I need to be able to perform Create, Read, Update, and Delete on all records via my <MaterialTable>s. I have Read, Update, and Delete working. The problem with Create is this:

The nested data (levels 2 and 3) are associated to their parent record by foreign key in my PostgreSQL database. I haven't found a way of getting the database ID of the parent record passed into the onRowAdd function. The parent's ID is passed into the nested <MaterialTable> as a hidden column, but the newData object passed to onRowAdd doesn't know the value of the parent.

A reproducible example is difficult, but here is some relevant, representative code:

<MaterialTable> code:

          <MaterialTable
            icons={tableIcons}
            title={'Level 1 Data'}
            columns={Object.keys(data[0])
              .filter(
                (el) =>
                  ![
                    'level_2_data',
                    'level_3_data',
                  ].includes(el),
              )
              .map((el) => col_to_definition(el))}
            data={data}
            editable={edit_fns}
            detailPanel={(rowData) => {
              return (
                rowData.level_2_data && (
                  <div
                    style={{
                      background: '#52b6e8',
                      padding: '10px 0px 10px 20px',
                    }}
                  >
                    {/* Level 2 Table */}
                    <MaterialTable
                      icons={tableIcons}
                      title={'Level 2 Data'}
                              columns={Object.keys(rowData.level_2_data[0])
                        .filter((el) => !['level_3_data'].includes(el))
                        .map((el) => col_to_definition(el))}
                      data={rowData.level_2_data}
                      editable={edit_fns}
                      detailPanel={(rowData) => {
                        return (
                          rowData.level_3_data && (
                            <div
                              style={{
                                background: '#d2ecf9',
                                padding: '10px 0px 10px 20px',
                              }}
                            >
                              {/* Level 3 Table */}
                              <MaterialTable
                                icons={tableIcons}
                                title={'Level 3 Data'}
                                columns={Object.keys(rowData.level_3_data[0])
                                  .map((el) => col_to_definition(el))}
                                data={rowData.level_3_data}
                                editable={edit_fns}
                              />
                            </div>
                          )
                        );
                      }}
                    />
                  </div>
                )
              );
            }}
          />

Edit Functions:

const edit_fns = {
    isEditable: (rowData) => true,
    isDeletable: (rowData) =>
        !rowData.level_2_data || rowData.level_2_data.length === 0
            ? true
            : false,
    onRowAdd: async (newData) => {
        const create_is_ok = createEntry('level_2', newData);
        if (create_is_ok) set_fetch_trigger(fetch_trigger + 1);
    },
    onRowUpdate: async (newData) => {
        const update_request_returned_ok = updateEntry('level_2', newData);
        if (update_request_returned_ok) set_fetch_trigger(fetch_trigger + 1);
    },
    onRowDelete: async (oldData) => {
        const delete_request_returned_ok = deleteEntry('level_2', oldData);
        if (delete_request_returned_ok) set_fetch_trigger(fetch_trigger + 1);
        return true;
    },
};
twgardner2
  • 630
  • 1
  • 8
  • 27

0 Answers0