Master-Detail React DataGrid with Charts
Tags: webdev, javascript, frontend, typescript
Published: 2024-06-10 15:12:28

In this article, I want to show you how easy it is to leverage the master-detail support in the [Infinite Table React DataGrid](https://infinite-table.com) in order to toggle between a table and a chart view in the row detail.

{% codesandbox gg7h4f %}

In the [RowDetail](https://infinite-table.com/docs/reference/infinite-table-props#components.RowDetail) component of Infinite Table, we render a `<DataSource />`, which in turn will render either an `<InfiniteTable />` component or a chart.

The `<DataSource />` in InfiniteTable is very powerful and does all the data processing the grid needs. All the row grouping, sorting, filtering, aggregations, pivoting are done in the `<DataSource />` - so you can use it standalone, or with InfiniteTable - it's totally up to you.

In practice, this means that you can use the `<DataSource />` to process your data and then simply pass that to a charting library like `ag-charts-react`.

```tsx
const detailGroupBy: DataSourcePropGroupBy<Developer> = [{ field: "stack" }];
const detailAggregationReducers: DataSourcePropAggregationReducers<Developer> =
  {
    salary: {
      field: "salary",
      initialValue: 0,
      reducer: (acc, value) => acc + value,
      done: (value, arr) => Math.round(arr.length ? value / arr.length : 0),
    },
  };

function RowDetail() {
  const rowInfo = useMasterRowInfo<City>()!;
  const [showChart, setShowChart] = React.useState(rowInfo.id % 2 == 1);

  return (
    <div style={{...}}>
      <button onClick={() => setShowChart((showChart) => !showChart)}>
        Click to see {showChart ? "grid" : "chart"}
      </button>

      {/**
       * In this example, we leverage the DataSource aggregation and grouping feature to
       * calculate the average salary by stack for the selected city.
       */}
      <DataSource<Developer>
        data={detailDataSource}
        primaryKey="id"
        groupBy={detailGroupBy}
        aggregationReducers={detailAggregationReducers}
      >
        {/**
         * Notice here we're not rendering an InfiniteTable component
         * but rather we use a render function to access the aggregated data.
         */}
        {(params) => {
          // here we decide if we need to show the chart or the grid
          if (!showChart) {
            return (
              <InfiniteTable
                columns={detailColumns}
                domProps={{
                  style: { paddingTop: 30 },
                }}
              />
            );
          }

          // the dataArray has all the aggregations and groupings done for us, 
          // so we need to retrieve the correct rows and pass it to the charting library
          const groups = params.dataArray.filter((rowInfo) => rowInfo.isGroupRow);
          const groupData = groups.map((group) => ({ stack: group.data?.stack, avgSalary: group.reducerData?.salary }));

          return (
            <AgChartsReact
              options={{
                autoSize: true,
                title: {
                  text: `Avg salary by stack in ${rowInfo.data?.name}, ${rowInfo.data?.country}`,
                },
                data: groupData,
                series: [
                  {
                    type: "bar",
                    xKey: "stack",
                    yKey: "avgSalary",
                    yName: "Average Salary",
                  },
                ],
              }}
            />
          );
        }}
      </DataSource>
    </div>
  );
}
```

The demo above is using the `ag-charts-react` package to render the charts.


Read more about the [rendering custom content in a master-detail setup](https://infinite-table.com/docs/learn/master-detail/custom-row-detail-content).