Languages

React - creating dynamic data table using primereact library

3 points
Asked by:
jan
1090

I am trying a create a reusable custom data table in React (tsx). I want to use the primereact library to create it. I want it to create it in a dynamic way that it should be able to handle sorting, dynamic type of data that is coming into the table (if it is date, it should format date, if it is text it should format that...) and so on. 

 

import React, { Component, ReactNode } from "react";

import { DataTable } from "primereact/datatable";
import { Checkbox } from "primereact/checkbox";
import { Column, ColumnProps } from "primereact/column";
import "primereact/resources/themes/mdc-dark-deeppurple/theme.css";
import "primereact/resources/primereact.min.css";
import "primeicons/primeicons.css";

import { PaginatorComponent } from "./paginatorComponent";

import "./customDataTable.css";


// Define the properties that the CustomDataTable component expects as input.
interface DataTableProps {
  data: any[];  // Input: The data to display in the table.
  checkbox: boolean;  // Input: Indicates whether to show checkboxes for row selection.
  sortField: string | null;  // Input: The field used for sorting.
  sortOrder: number;  // Input: The sorting order (1 for ascending, -1 for descending).
  onSortChange: (field: string, order: number) => void;  // Output: Callback for sorting change.
  onSelectionChange: (selectedRows: any[], selectAll: boolean) => void;  // Output: Callback for selection change.
  scrollHeight?: string;  // Input: Height for the table with a scrollbar.
  scrollWidth?: string;  // Input: Width for the table with a scrollbar.
  columnRenderers?: Record<string, (cellData: any) => ReactNode>;  // Input: Renderers for custom column data.
  children?: ReactNode;  // Child components, which are the columns of the table.
  scrollable?: boolean;  // Input: Indicates whether the table should be scrollable.
}

// Define the state structure for the CustomDataTable component.
interface DataTableState {
  currentPage: number;  // Current page of the table.
  selectedRows: any[];  // Selected rows in the table.
  dataToDisplay: any[];  // Data to display in the table.
  selectAll: boolean;  // Indicates whether all rows are selected.
  itemsPerPage: number;  // Number of items to display per page.
}

// Define the CustomDataTable component.
class CustomDataTable extends Component<DataTableProps, DataTableState> {
  // Constructor for the component, initializing state and binding methods.
  constructor(props: DataTableProps) {
    super(props);
    this.state = {
      currentPage: 1,
      selectedRows: [],
      dataToDisplay: this.props.data,
      selectAll: false,
      itemsPerPage: 3,
    };
  }
  
  // componentDidUpdate is called when props change, used for sorting updates.
  componentDidUpdate(prevProps: DataTableProps, prevState: DataTableState) {
    if (
      prevProps.data !== this.props.data ||
      prevProps.sortField !== this.props.sortField ||
      prevProps.sortOrder !== this.props.sortOrder
    ) {
      this.sortData();
    }
  }
  
  // Callback for changing the current page.
  handlePageChange = (newPage: number) => {
    this.setState({ currentPage: newPage });
  }; // Toggle the selection of all rows in the table.

  toggleAllRows = () => {
    const { selectAll, dataToDisplay } = this.state;
    if (selectAll) {
      // If all rows are already selected, clear the selection.
      this.setState({ selectedRows: [] });
    } else {
      // If not all rows are selected, select all of them.
      this.setState({ selectedRows: [...dataToDisplay] });
    } // Toggle the selectAll flag and trigger the onSelectionChange callback.
    this.setState({ selectAll: !selectAll }, () => {
      this.props.onSelectionChange(this.state.selectedRows, !selectAll);
    });
  };
  
  // Toggle the selection of a single row.
  toggleRow = (rowData: any) => {
    const { selectedRows } = this.state;
    const rowIndex = selectedRows.findIndex((row) => row.id === rowData.id);
    if (rowIndex === -1) {
      // If the row is not selected, add it to the selection.
      this.setState(
        { selectedRows: [...selectedRows, rowData], selectAll: false },
        () => {
          this.props.onSelectionChange(this.state.selectedRows, false);
        }
      );
    } else {
      // If the row is already selected, remove it from the selection.
      const newSelectedRows = [...selectedRows];
      newSelectedRows.splice(rowIndex, 1);
      this.setState({ selectedRows: newSelectedRows, selectAll: false }, () => {
        this.props.onSelectionChange(newSelectedRows, false);
      });
    }
  };
  
  // Sort the data based on the selected sort field and order.
  sortData = () => {
    const { sortField, sortOrder } = this.props;
    if (sortField) {
      // Create a sorted copy of the data based on the sortField and sortOrder.
      const sorted = [...this.state.dataToDisplay].sort((a, b) => {
        const aValue = a[sortField];
        const bValue = b[sortField]; // Determine if the field values are numerical.
        const isNumerical = !isNaN(parseFloat(aValue)) && !isNaN(parseFloat(bValue));
        let result = 0;
        if (isNumerical) {
          // If the values are numerical, compare them directly.
          result = sortOrder === 1 ? aValue - bValue : bValue - aValue;
        } else {
          // If the values are not numerical, perform a string-based comparison.
          result = sortOrder === 1 ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
        }
        return result;
      });
      // Update the dataToDisplay state with the sorted data.
      this.setState({ dataToDisplay: sorted });
    }
  };
  
  // Callback for changing the number of items per page.
  handleItemsPerPageChange = (itemsPerPage: number) => {
    this.setState({ itemsPerPage }, () => {
      this.updateDisplayedData();
    });
  };
  
  // Update the displayed data based on the current page and items per page.
  updateDisplayedData = () => {
    const { currentPage, itemsPerPage } = this.state;
    const startIndex = (currentPage - 1) * itemsPerPage;
    const endIndex = startIndex + itemsPerPage;
    const dataToDisplayPaginated = this.state.dataToDisplay.slice(
      startIndex,
      endIndex
    );
    console.log(dataToDisplayPaginated);
  };
  
  // Callback for sorting column data when a column header is clicked.
  handleSortClick = (field: string) => {
    const { sortField, sortOrder } = this.props;
    if (field === sortField) {
      this.props.onSortChange(field, sortOrder === 1 ? -1 : 1);
    } else {
      this.props.onSortChange(field, 1);
    }
  };
  
  // Lifecycle method called after the component is mounted.
  componentDidMount() {
    console.log(`Initial Sorting Direction: ${this.props.sortOrder}`);
  }
  
  // Render method for the component.
  render() {
    const {
      currentPage,
      selectedRows,
      dataToDisplay,
      selectAll,
      itemsPerPage,
    } = this.state;
    const { checkbox } = this.props;  // Calculate the index range for the current page.
    const startIndex = (currentPage - 1) * itemsPerPage;
    const endIndex = startIndex + itemsPerPage;
    const dataToDisplayPaginated = dataToDisplay.slice(startIndex, endIndex);
    return (
      <div className="custom-data-table-container">
        {" "}
        <div className="custom-data-table">
          {" "}
          <DataTable
            value={dataToDisplayPaginated}
            stripedRows
            scrollable
            className="custom-data-table-scroll"
          >
            {" "}
            {/* Check if the checkbox option is enabled and add checkbox column if true. */}
            {" "}
            {checkbox && (
              <Column
                key="checkbox"
                header={
                  <Checkbox
                    className="custom-checkbox"
                    checked={selectAll}
                    onChange={this.toggleAllRows}
                  />
                }
                body={(rowData) => (
                  <Checkbox
                    className="custom-checkbox"
                    checked={selectedRows.some((row) => row.id === rowData.id)}
                    onChange={() => this.toggleRow(rowData)}
                  />
                )}
              />
            )}
            {" "}
            {React.Children.map(this.props.children, (child: ReactNode) => {
              // Use React.Children.map to iterate over the child elements passed to the component.
              if (React.isValidElement<ColumnProps>(child)) {
                // Check if the child is a valid React element with a specific type, here Column component.
                return React.cloneElement(
                  child as React.ReactElement<ColumnProps>,
                  {
                    // Clone the child element and potentially modify its props.
                    // child as React.ReactElement<ColumnProps> casts the child element as a Column with specific props.
                  }
                );
              }
              // If the child is not a valid Column component, return null.
              return null;
            })}
            {" "}
          </DataTable>
          {" "}
        </div>
        {" "}
        <PaginatorComponent
          totalItems={this.props.data.length}
          itemsPerPage={itemsPerPage}
          currentPage={currentPage}
          onPageChange={this.handlePageChange}
          rowsCountOptions={[3, 5, 10, 20]}
        />
        {" "}
      </div>
    );
  }
}

// Export the CustomDataTable component.
export default CustomDataTable;

 

Attaching my code for reference, I added comments so that you wil not confuse. I need help in creating the row renderer function, so that I can pass dynamic data without again defining what kind of data it is in my component where I am using this data table. If i date in my dynamic data, it should be able to pass it in date format. If it is text it should be able to pass that format. Please help me with this, as I am a beginner to this. Thanks in advance

3 comments
Root-ssh
Maybe you should use this function https://dirask.com/posts/1GRMqj ?
Root-ssh
As I see, yours source code causes infinite re-rendering cycles inside DataTable component.
jan
I don&#39;t want to compare the data and all. I want to pass different regex so that my data can accept and display the readable format. And coming to another function that I requested for help should allow me to add filters, sorting and all in my column header only. And coming to the re-rendering I am new to react and I am trying my best . I am trying to fix that.
Add comment
2 answers
6 points
Answered by:
jan
1090

Automatically generated columns can be achieved using:

import React, { Component, ReactNode } from "react";

import { DataTable } from "primereact/datatable";
import { Checkbox } from "primereact/checkbox";
import { Column, ColumnProps } from "primereact/column";
import "primereact/resources/themes/mdc-dark-deeppurple/theme.css";
import "primereact/resources/primereact.min.css";
import "primeicons/primeicons.css";

import { PaginatorComponent } from "./paginatorComponent";

import "./customDataTable.css";


// Source: https://dirask.com/snippets/JavaScript-detect-column-names-in-data-rows-D9ooaj
//
const findColumns = (rows: any[]): string[] => {
  const columns = {} as Record<string, true>;
  for (const row of rows) {
      for (const name in row) {
         columns[name] = true;
      }
  }
  return Object.keys(columns);
};

// Define the properties that the CustomDataTable component expects as input.
interface DataTableProps {
  data: any[];  // Input: The data to display in the table.
  checkbox: boolean;  // Input: Indicates whether to show checkboxes for row selection.
  sortField: string | null;  // Input: The field used for sorting.
  sortOrder: number;  // Input: The sorting order (1 for ascending, -1 for descending).
  onSortChange: (field: string, order: number) => void;  // Output: Callback for sorting change.
  onSelectionChange: (selectedRows: any[], selectAll: boolean) => void;  // Output: Callback for selection change.
  scrollHeight?: string;  // Input: Height for the table with a scrollbar.
  scrollWidth?: string;  // Input: Width for the table with a scrollbar.
  children?: ReactNode;  // Child components, which are the columns of the table.
  scrollable?: boolean;  // Input: Indicates whether the table should be scrollable.
}

// Define the state structure for the CustomDataTable component.
interface DataTableState {
  currentPage: number;  // Current page of the table.
  selectedRows: any[];  // Selected rows in the table.
  dataToDisplay: any[];  // Data to display in the table.
  selectAll: boolean;  // Indicates whether all rows are selected.
  itemsPerPage: number;  // Number of items to display per page.
}

// Define the CustomDataTable component.
class CustomDataTable extends Component<DataTableProps, DataTableState> {
  // Constructor for the component, initializing state and binding methods.
  constructor(props: DataTableProps) {
    super(props);
    this.state = {
      currentPage: 1,
      selectedRows: [],
      dataToDisplay: this.props.data,
      selectAll: false,
      itemsPerPage: 3,
    };
  }
  
  // componentDidUpdate is called when props change, used for sorting updates.
  componentDidUpdate(prevProps: DataTableProps, prevState: DataTableState) {
    if (
      prevProps.data !== this.props.data ||
      prevProps.sortField !== this.props.sortField ||
      prevProps.sortOrder !== this.props.sortOrder
    ) {
      this.sortData();
    }
  }
  
  // Callback for changing the current page.
  handlePageChange = (newPage: number) => {
    this.setState({ currentPage: newPage });
  }; // Toggle the selection of all rows in the table.

  toggleAllRows = () => {
    const { selectAll, dataToDisplay } = this.state;
    if (selectAll) {
      // If all rows are already selected, clear the selection.
      this.setState({ selectedRows: [] });
    } else {
      // If not all rows are selected, select all of them.
      this.setState({ selectedRows: [...dataToDisplay] });
    } // Toggle the selectAll flag and trigger the onSelectionChange callback.
    this.setState({ selectAll: !selectAll }, () => {
      this.props.onSelectionChange(this.state.selectedRows, !selectAll);
    });
  };
  
  // Toggle the selection of a single row.
  toggleRow = (rowData: any) => {
    const { selectedRows } = this.state;
    const rowIndex = selectedRows.findIndex((row) => row.id === rowData.id);
    if (rowIndex === -1) {
      // If the row is not selected, add it to the selection.
      this.setState(
        { selectedRows: [...selectedRows, rowData], selectAll: false },
        () => {
          this.props.onSelectionChange(this.state.selectedRows, false);
        }
      );
    } else {
      // If the row is already selected, remove it from the selection.
      const newSelectedRows = [...selectedRows];
      newSelectedRows.splice(rowIndex, 1);
      this.setState({ selectedRows: newSelectedRows, selectAll: false }, () => {
        this.props.onSelectionChange(newSelectedRows, false);
      });
    }
  };
  
  // Sort the data based on the selected sort field and order.
  sortData = () => {
    const { sortField, sortOrder } = this.props;
    if (sortField) {
      // Create a sorted copy of the data based on the sortField and sortOrder.
      const sorted = [...this.state.dataToDisplay].sort((a, b) => {
        const aValue = a[sortField];
        const bValue = b[sortField]; // Determine if the field values are numerical.
        const isNumerical = !isNaN(parseFloat(aValue)) && !isNaN(parseFloat(bValue));
        let result = 0;
        if (isNumerical) {
          // If the values are numerical, compare them directly.
          result = sortOrder === 1 ? aValue - bValue : bValue - aValue;
        } else {
          // If the values are not numerical, perform a string-based comparison.
          result = sortOrder === 1 ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
        }
        return result;
      });
      // Update the dataToDisplay state with the sorted data.
      this.setState({ dataToDisplay: sorted });
    }
  };
  
  // Callback for changing the number of items per page.
  handleItemsPerPageChange = (itemsPerPage: number) => {
    this.setState({ itemsPerPage }, () => {
      this.updateDisplayedData();
    });
  };
  
  // Update the displayed data based on the current page and items per page.
  updateDisplayedData = () => {
    const { currentPage, itemsPerPage } = this.state;
    const startIndex = (currentPage - 1) * itemsPerPage;
    const endIndex = startIndex + itemsPerPage;
    const dataToDisplayPaginated = this.state.dataToDisplay.slice(
      startIndex,
      endIndex
    );
    console.log(dataToDisplayPaginated);
  };
  
  // Callback for sorting column data when a column header is clicked.
  handleSortClick = (field: string) => {
    const { sortField, sortOrder } = this.props;
    if (field === sortField) {
      this.props.onSortChange(field, sortOrder === 1 ? -1 : 1);
    } else {
      this.props.onSortChange(field, 1);
    }
  };
  
  // Lifecycle method called after the component is mounted.
  componentDidMount() {
    console.log(`Initial Sorting Direction: ${this.props.sortOrder}`);
  }
  
  // Render method for the component.
  render() {
    let columnNames = findColumns(this.props.data);  // <----------------------- https://dirask.com/snippets/JavaScript-detect-column-names-in-data-rows-D9ooaj
    const {
      currentPage,
      selectedRows,
      dataToDisplay,
      selectAll,
      itemsPerPage,
    } = this.state;
    const { checkbox } = this.props;  // Calculate the index range for the current page.
    const startIndex = (currentPage - 1) * itemsPerPage;
    const endIndex = startIndex + itemsPerPage;
    const dataToDisplayPaginated = dataToDisplay.slice(startIndex, endIndex);
    return (
      <div className="custom-data-table-container">
        {" "}
        <div className="custom-data-table">
          {" "}
          <DataTable
            value={dataToDisplayPaginated}
            stripedRows
            scrollable
            className="custom-data-table-scroll"
          >
            {" "}
            {/* Check if the checkbox option is enabled and add checkbox column if true. */}
            {" "}
            {checkbox && (
              <Column
                key="checkbox"
                header={
                  <Checkbox
                    className="custom-checkbox"
                    checked={selectAll}
                    onChange={this.toggleAllRows}
                  />
                }
                body={(rowData) => (
                  <Checkbox
                    className="custom-checkbox"
                    checked={selectedRows.some((row) => row.id === rowData.id)}
                    onChange={() => this.toggleRow(rowData)}
                  />
                )}
              />
            )}
            {" "}
            {columnNames.map((columnName: string, columnIndex: number) => {  // <-----------------------
              return (                                                       // <-----------------------
                <Column                                                      // <-----------------------
                  key={columnName ?? columnIndex}                            // <-----------------------
                  header={columnName}                                        // <-----------------------
                  body={(rowData) => {                                       // <-----------------------
                    const cellData = rowData[columnName];                    // <-----------------------
                    if (cellData == null) {  // null or undefined            // <-----------------------
                      return '';                                             // <-----------------------
                    }                                                        // <-----------------------
                    switch (typeof cellData) {                               // <-----------------------
                      case 'boolean':                                        // <-----------------------
                      case 'number':                                         // <-----------------------
                      case 'string':                                         // <-----------------------
                        return String(cellData);                             // <-----------------------
                      default:                                               // <-----------------------
                        if (cellData instanceof Date) {                      // <-----------------------
                          return String(cellData); //TODO: add formatter     // <-----------------------
                        }                                                    // <-----------------------
                        //TODO: add other cases here...                      // <-----------------------
                        return '';                                           // <-----------------------
                    }                                                        // <-----------------------
                  }}                                                         // <-----------------------
                />                                                           // <-----------------------
              );                                                             // <-----------------------
            })}
            {" "}
          </DataTable>
          {" "}
        </div>
        {" "}
        <PaginatorComponent
          totalItems={this.props.data.length}
          itemsPerPage={itemsPerPage}
          currentPage={currentPage}
          onPageChange={this.handlePageChange}
          rowsCountOptions={[3, 5, 10, 20]}
        />
        {" "}
      </div>
    );
  }
}

// Export the CustomDataTable component.
export default CustomDataTable;

 

0 comments Add comment
1 points
Answered by:
jan
1090

Columns and rows rendering can be achieved using mapping:

// ...
const columnRenderers = this.props.columnRenderers as any;
const columnKeys = Object.keys(columnRenderers);
// ...
{columnKeys.map((columnKey: string, columnIndex: number) => {
  return (
    <Column
      key={columnKey ?? columnIndex}
      header={columnKey}
      body={(rowData) => String(rowData[columnKey])}
    />
  );
})}
// ...

Hint: change String(rowData[columnKey]) to proper redering.

 

Practical example

CustomDataTable component:

import React, { Component, ReactNode } from "react";

import { DataTable } from "primereact/datatable";
import { Checkbox } from "primereact/checkbox";
import { Column, ColumnProps } from "primereact/column";
import "primereact/resources/themes/mdc-dark-deeppurple/theme.css";
import "primereact/resources/primereact.min.css";
import "primeicons/primeicons.css";

import { PaginatorComponent } from "./paginatorComponent";

import "./customDataTable.css";


// Define the properties that the CustomDataTable component expects as input.
interface DataTableProps {
  data: any[];  // Input: The data to display in the table.
  checkbox: boolean;  // Input: Indicates whether to show checkboxes for row selection.
  sortField: string | null;  // Input: The field used for sorting.
  sortOrder: number;  // Input: The sorting order (1 for ascending, -1 for descending).
  onSortChange: (field: string, order: number) => void;  // Output: Callback for sorting change.
  onSelectionChange: (selectedRows: any[], selectAll: boolean) => void;  // Output: Callback for selection change.
  scrollHeight?: string;  // Input: Height for the table with a scrollbar.
  scrollWidth?: string;  // Input: Width for the table with a scrollbar.
  columnRenderers?: Record<string, (cellData: any) => ReactNode>;  // Input: Renderers for custom column data.
  children?: ReactNode;  // Child components, which are the columns of the table.
  scrollable?: boolean;  // Input: Indicates whether the table should be scrollable.
}

// Define the state structure for the CustomDataTable component.
interface DataTableState {
  currentPage: number;  // Current page of the table.
  selectedRows: any[];  // Selected rows in the table.
  dataToDisplay: any[];  // Data to display in the table.
  selectAll: boolean;  // Indicates whether all rows are selected.
  itemsPerPage: number;  // Number of items to display per page.
}

// Define the CustomDataTable component.
class CustomDataTable extends Component<DataTableProps, DataTableState> {
  // Constructor for the component, initializing state and binding methods.
  constructor(props: DataTableProps) {
    super(props);
    this.state = {
      currentPage: 1,
      selectedRows: [],
      dataToDisplay: this.props.data,
      selectAll: false,
      itemsPerPage: 3,
    };
  }
  
  // componentDidUpdate is called when props change, used for sorting updates.
  componentDidUpdate(prevProps: DataTableProps, prevState: DataTableState) {
    if (
      prevProps.data !== this.props.data ||
      prevProps.sortField !== this.props.sortField ||
      prevProps.sortOrder !== this.props.sortOrder
    ) {
      this.sortData();
    }
  }
  
  // Callback for changing the current page.
  handlePageChange = (newPage: number) => {
    this.setState({ currentPage: newPage });
  }; // Toggle the selection of all rows in the table.

  toggleAllRows = () => {
    const { selectAll, dataToDisplay } = this.state;
    if (selectAll) {
      // If all rows are already selected, clear the selection.
      this.setState({ selectedRows: [] });
    } else {
      // If not all rows are selected, select all of them.
      this.setState({ selectedRows: [...dataToDisplay] });
    } // Toggle the selectAll flag and trigger the onSelectionChange callback.
    this.setState({ selectAll: !selectAll }, () => {
      this.props.onSelectionChange(this.state.selectedRows, !selectAll);
    });
  };
  
  // Toggle the selection of a single row.
  toggleRow = (rowData: any) => {
    const { selectedRows } = this.state;
    const rowIndex = selectedRows.findIndex((row) => row.id === rowData.id);
    if (rowIndex === -1) {
      // If the row is not selected, add it to the selection.
      this.setState(
        { selectedRows: [...selectedRows, rowData], selectAll: false },
        () => {
          this.props.onSelectionChange(this.state.selectedRows, false);
        }
      );
    } else {
      // If the row is already selected, remove it from the selection.
      const newSelectedRows = [...selectedRows];
      newSelectedRows.splice(rowIndex, 1);
      this.setState({ selectedRows: newSelectedRows, selectAll: false }, () => {
        this.props.onSelectionChange(newSelectedRows, false);
      });
    }
  };
  
  // Sort the data based on the selected sort field and order.
  sortData = () => {
    const { sortField, sortOrder } = this.props;
    if (sortField) {
      // Create a sorted copy of the data based on the sortField and sortOrder.
      const sorted = [...this.state.dataToDisplay].sort((a, b) => {
        const aValue = a[sortField];
        const bValue = b[sortField]; // Determine if the field values are numerical.
        const isNumerical = !isNaN(parseFloat(aValue)) && !isNaN(parseFloat(bValue));
        let result = 0;
        if (isNumerical) {
          // If the values are numerical, compare them directly.
          result = sortOrder === 1 ? aValue - bValue : bValue - aValue;
        } else {
          // If the values are not numerical, perform a string-based comparison.
          result = sortOrder === 1 ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
        }
        return result;
      });
      // Update the dataToDisplay state with the sorted data.
      this.setState({ dataToDisplay: sorted });
    }
  };
  
  // Callback for changing the number of items per page.
  handleItemsPerPageChange = (itemsPerPage: number) => {
    this.setState({ itemsPerPage }, () => {
      this.updateDisplayedData();
    });
  };
  
  // Update the displayed data based on the current page and items per page.
  updateDisplayedData = () => {
    const { currentPage, itemsPerPage } = this.state;
    const startIndex = (currentPage - 1) * itemsPerPage;
    const endIndex = startIndex + itemsPerPage;
    const dataToDisplayPaginated = this.state.dataToDisplay.slice(
      startIndex,
      endIndex
    );
    console.log(dataToDisplayPaginated);
  };
  
  // Callback for sorting column data when a column header is clicked.
  handleSortClick = (field: string) => {
    const { sortField, sortOrder } = this.props;
    if (field === sortField) {
      this.props.onSortChange(field, sortOrder === 1 ? -1 : 1);
    } else {
      this.props.onSortChange(field, 1);
    }
  };
  
  // Lifecycle method called after the component is mounted.
  componentDidMount() {
    console.log(`Initial Sorting Direction: ${this.props.sortOrder}`);
  }
  
  // Render method for the component.
  render() {
    const columnRenderers = this.props.columnRenderers as any;  // <-----------------------
    const columnKeys = Object.keys(columnRenderers);            // <-----------------------
    const {
      currentPage,
      selectedRows,
      dataToDisplay,
      selectAll,
      itemsPerPage,
    } = this.state;
    const { checkbox } = this.props;  // Calculate the index range for the current page.
    const startIndex = (currentPage - 1) * itemsPerPage;
    const endIndex = startIndex + itemsPerPage;
    const dataToDisplayPaginated = dataToDisplay.slice(startIndex, endIndex);
    return (
      <div className="custom-data-table-container">
        {" "}
        <div className="custom-data-table">
          {" "}
          <DataTable
            value={dataToDisplayPaginated}
            stripedRows
            scrollable
            className="custom-data-table-scroll"
          >
            {" "}
            {/* Check if the checkbox option is enabled and add checkbox column if true. */}
            {" "}
            {checkbox && (
              <Column
                key="checkbox"
                header={
                  <Checkbox
                    className="custom-checkbox"
                    checked={selectAll}
                    onChange={this.toggleAllRows}
                  />
                }
                body={(rowData) => (
                  <Checkbox
                    className="custom-checkbox"
                    checked={selectedRows.some((row) => row.id === rowData.id)}
                    onChange={() => this.toggleRow(rowData)}
                  />
                )}
              />
            )}
            {" "}
            {columnKeys.map((columnKey: string, columnIndex: number) => {  // <-----------------------
              return (                                                     // <-----------------------
                <Column                                                    // <-----------------------
                  key={columnKey ?? columnIndex}                           // <-----------------------
                  header={columnKey}                                       // <-----------------------
                  body={(rowData) => {                                     // <-----------------------
                    const columnRenderer = columnRenderers[columnKey];     // <-----------------------
                    return columnRenderer(rowData);                        // <-----------------------
                  }}                                                       // <-----------------------
                />                                                         // <-----------------------
              );                                                           // <-----------------------
            })}
            {" "}
          </DataTable>
          {" "}
        </div>
        {" "}
        <PaginatorComponent
          totalItems={this.props.data.length}
          itemsPerPage={itemsPerPage}
          currentPage={currentPage}
          onPageChange={this.handlePageChange}
          rowsCountOptions={[3, 5, 10, 20]}
        />
        {" "}
      </div>
    );
  }
}

// Export the CustomDataTable component.
export default CustomDataTable;

 

Example usage:

<CustomDataTable
  data={[
    {id: 1, name: 'aaa'},
    {id: 2, name: 'bbb'},
    {id: 3, name: 'ccc'},
    {id: 4, name: 'ddd'}
  ]}
  checkbox={true}
  sortField="id"
  sortOrder={-1}
  onSortChange={(field: string, order: number): void => {}}
  onSelectionChange={(selectedRows: any[], selectAll: boolean): void => {}}
  columnRenderers={{
    id: (rowData: any): ReactNode => {
      return <>{String(rowData.id)}</>;
    },
    name: (cellData: any): ReactNode => {
      return <>{String(rowData.name)}</>;
    }
  }}
/>

Example preview:

4 comments
jan
columnRenderers&#61;{{ id: (cellData: any): ReactNode &#61;&gt; { return &lt;&gt;{String(cellData)}&lt;/&gt;; }, name: (cellData: any): ReactNode &#61;&gt; { return &lt;&gt;{String(cellData)}&lt;/&gt;; } I appreciate your help. But I am having a couple of questions with this approach. Why to pass the column renderer as a prop in customdata table component? Why can&#39;t we add a functional component in the custom data table component which is holding few formats like stringformatter, dateformatter, IPaddressformatter etc...! If I have raw date coming from the data, I should be able to use it on the row that I want to get date format. I am using custom column component from primereact to render the columns. I don&#39;t want to pass them as an array because I am completely having dynamic data. The column component is having a prop called &#39;body&#39; which will render the functions. So as an example bodyr&#61;{this.abcRenderer} . This abcRenderer is abcrenderer &#61; {bodyRenderer.stringFormat(data.abc)}. Like this. This things should be handled from my data table component only.
jan
And one more thing is like, if I don&#39;t pass any bodyRenderer then it should show the raw data. I tried and able to add the renderer function but I am unable to get the rowdata. Can you please help me with this!
Root-ssh
&#64;&#39;pranathi tammina&#39;, answering for &#34;Why to pass the column renderer as a prop in customdata table component?&#34;, &#96;columnRenderers&#96; property was in the CustomDataTable props you shared in the source code snippet - it wasn&#39;t used causing not working the component.
Root-ssh
Inside CustomDataTable component you can add logic that detects column names from data (check this snippet: https://dirask.com/snippets/JavaScript-detect-column-names-in-data-rows-D9ooaj).
Add comment
Donate to Dirask
Our content is created by volunteers - like Wikipedia. If you think, the things we do are good, donate us. Thanks!
Join to our subscribers to be up to date with content, news and offers.
Native Advertising
🚀
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

❤️💻 🙂

Join