DEV Community

Radu Brehar👨‍💻
Radu Brehar👨‍💻

Posted on • Originally published at infinite-table.com

Master-Detail React DataGrid with Charts

In this article, I want to show you how easy it is to leverage the master-detail support in the Infinite Table React DataGrid in order to toggle between a table and a chart view in the row detail.

In the 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.

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)