Pit Viper

v2.26.1

Pit Viper

v2.26.1
v1 / v2

  • Home
  • PV Components
  • PvDataTable

PvDataTable

Documentation

Overview

The PvDataTable component is a wrapper for the AG grid library, which provides the following

  • A data table component that supports sorting, filtering, and grouping (using both client and server side data)
  • A custom filter panel implementation
  • A built in Pit Viper theme, with the option to customize if needed
  • The ability to export data as a CSV
  • Exposes AG grid functionality for advanced use, such as custom cell rendering.

This component abstracts a lot of standard functionality in the AG grid library to make implementation easier, but
does not include all of the functionality that AG grid provides. For advanced usage, refer to the “Grid API” section below.

Column Definitions

The colDefs property is used to define the columns of the table, and follows the AG Grid format.
This is where you define the column header names, the field they correspond to in the row data, and any additional parameters needed for that column. Several common ones are

  • sortable (default: true) - whether the column is sortable
  • filter (default: null) - which filter to use for this column. Currently only agSetColumnFilter is supported
  • enableRowGroup (default: false) - whether the column can be grouped by
    An example of a column definition is shown below:
  {
    field: "provider_name",
    headerName: "Provider",
    enableRowGroup: false,
    filter: "agSetColumnFilter",
    minWidth: 310,
    context: {
      dataType: "entity",
    } as ColDefContextProps,
    // This line is applied to the row cell and automatically takes the value from rowData['provider_name'].
    tooltipField: "provider_name",
    headerTooltip: "This value will show when the user hovers over the column header.",
    // You can pass a dynamic value for the row cell using tooltipValueGetter.
    // IMPORTANT: Do not use tooltipField and tooltipValueGetter together, as they may conflict with each other.
    tooltipValueGetter: (p) => `Super Dynamic Value ${p.value}`
  }

Context

The optional context property is where we pass properties that are not natively supported by AG grid, such as

  • visibilityState?: “alwaysShow” | “alwaysHide”; // whether the column should always be shown or hidden (unaffected by the visibility panel)
  • dataType?: ColDefDataType; // type of data in the column, used to render the cell differently
  • filterSelectMax?: number; // max number of items that can be selected in the filter

ValueFormatter

The valueFormatter property can be used to format the value of a cell. This is useful for formatting
values based on some logic. The dataType context prop is used to automatically format values, i.e. currency will format the value as a currency.
The value formatter will apply to all cells of that column.
Full documentation for the AG grid value formatter is available here.

Cell Renderer

Similar to the ValueFormatter, the CellRenderer will add custom rendering to all cells in a column. This is useful
for adding columns that need to display a link in a cell or other custom rendering.

cellRenderer: params => {
const value = params.value ?? params.valueFormatted;
if (!value || typeof value !== "object" || value.text === "-") {
return `
<span class="pv-flex pv-full-width pv-space-between">
<span></span>
<span>-</span>
</span>
`;
}

Full documentation for the AG grid cell renderer is available here.

View the Properties table below for a complete list of properties that can be used to configure the component.

Client-side Data

If the amount of data being supplied to the grid is <20,000 rows, the recommended approach is to use client-side data,
as it simplifies the implementation and handles the filtering/sorting/grouping logic automatically. For client-side data,
all that is required is the rowData prop, which needs to be an array of objects with keys that match the field values in the colDefs prop.
Additional keys can be present, but they will be ignored by the grid.
Example row data is shown below:

[
{
	provider_name: "Cherry Creek Hospital",
	payer_name: "Aetna",
	payer_type: "PPO",
	payer_class: "Commercial",
},
{
	provider_name: "Cherry Creek Hospital",
	payer_name: "Blue Cross",
	payer_type: "HMO",
	payer_class: "Commercial",
},
{
	provider_name: "Banner Health",
	payer_name: "Blue Cross",
	payer_type: "HMO",
	payer_class: "Commercial",
}
]

Server-side Data

TODO

filterValuesSetHandler

TODO

Setting Initial State

If your grid has any filters/groups or sorts applied by default without requiring user interaction, you can provide the desired state
via the initialState prop. This is a native AG grid object that contains properties like the sort order, grouped columns, and current filters.
An example initial state:

{
  filter: {
    filterModel: {
      payer_type: {
        values: ["HMO"],
        filterType: "set",
      },
    },
  },
  rowGroup: {
    groupColIds: ["provider_name", "bill_type"],
  },
  sort: {
    sortModel: [{ colId: "yield", sort: "desc" }],
  },
  partialColumnState: true,
}

The full state object model can be found in the AG grid documentation here. Please note that not all
of these properties may be supported by the component. Currently group
NOTE - you will almost always need to provide partialColumnState: true in the state object, unless every potential property is declared in the initialState object.

Grid API

The AG Grid API can be used to access the full functionality of the AG grid library.
The API is exposed via most of the events emitted by the component, but the easiest (and earliest) one is the grid-ready event, which is emitted when the grid is initialized.
An example of how to attach to the api is shown below:

<!--<script>-->
const gridApi = ref(null);
const handleGridReady = (params) => {
	gridApi.value = params.api;
};
<!--</script>-->
<!--<template>-->
<PvDataTable @grid-ready="handleGridReady"></PvDataTable>
<!--</template>-->

*NOTE* - It is not recommended to use the grid API directly, as it can interfere with the component's internal state management. Instead, it is suggested to use the component's interfaces wherever possible, and if additional functionality is needed, to contact the design systems team to see if it makes sense to add it to the component.

Events

View the events table below to see the specific events that are currently emitted by the component. These events all originate
from the AG grid component, and so full documentation for them is available here.

What is not yet supported:

  • pivoting
  • numeric and text based filters

AG Grid documentation links

Example

Source

HTML
<script setup lang="ts">
import PvDataTable from "@tables/PvDataTable/PvDataTable.vue";
import { ColDef } from "ag-grid-community";
import { ref } from "vue"; // Ensure ref is imported
import { ColDefContextProps } from "@tables/PvDataTable/PvDataTable.vue";
interface RowDataFormat {
provider_name: string;
payer_name: string;
payer_type: string;
payer_class: string;
provider_type: string;
bill_type: string;
npi: string;
service_category: string;
code: string;
rate: number;
yield: number;
}

const colDefs: ColDef[] = [
{
field: "provider_name",
headerName: "Provider",
enableRowGroup: false,
filter: "agSetColumnFilter",
minWidth: 310,
context: {
dataType: "entity",
} as ColDefContextProps<RowDataFormat>,
tooltipField: "provider_name",
headerTooltip: "Tooltip for Provider Column Header",
},
{
field: "payer_name",
headerName: "Payer",
enableRowGroup: false,
filter: "agSetColumnFilter",
context: {
dataType: "entity",
filterSelectMax: 1,
} as ColDefContextProps<RowDataFormat>,
},
{
field: "rate",
headerName: "Rate",
aggFunc: "Median",
enableValue: true,
allowedAggFuncs: ["min", "max", "Median"],
context: {
dataType: "currency",
} as ColDefContextProps<RowDataFormat>,
tooltipValueGetter: (p) => "Dynamic Rate Value: " + p.value,
},
{
field: "yield",
headerName: "Yield",
aggFunc: "sum",
enableValue: true,
allowedAggFuncs: ["sum", "min", "Median"],
context: {
dataType: "formula",
} as ColDefContextProps<RowDataFormat>,
},
{
field: "payer_type",
headerName: "Payer Type",
enableRowGroup: false,
filter: "agSetColumnFilter",
},
{
field: "payer_class",
headerName: "Payer Class",
enableRowGroup: true,
filter: "agSetColumnFilter",
},
{
field: "provider_type",
headerName: "Provider Type",
enableRowGroup: true,
filter: "agSetColumnFilter",
},
{
field: "bill_type",
headerName: "Bill Type",
enableRowGroup: true,
filter: "agSetColumnFilter",
context: {
dataType: "tag",
} as ColDefContextProps<RowDataFormat>,
},
{
field: "npi",
headerName: "NPI",
filter: "agSetColumnFilter",
context: {
dataType: "id",
} as ColDefContextProps<RowDataFormat>,
},
{
field: "service_category",
headerName: "Service Category",
enableRowGroup: true,
filter: "agSetColumnFilter",
},
{
field: "code",
headerName: "Code",
enableRowGroup: true,
filter: "agSetColumnFilter",
context: {
dataType: "select",
} as ColDefContextProps<RowDataFormat>,
},
];

const generateSampleData = (count: number): RowDataFormat[] => {
const data: RowDataFormat[] = [];
for (let i = 1; i <= count; i++) {
data.push({
provider_name: `Provider Example ${String.fromCharCode(65 + (i % 26))}${Math.floor(i / 26) || ""}`,
payer_name: `Payer Example ${i % 5 === 0 ? "Alpha" : i % 3 === 0 ? "Beta" : "Gamma"}`,
payer_type: i % 2 === 0 ? "PPO" : "HMO",
payer_class: "Commercial",
provider_type: "Short Term Acute Care",
bill_type: i % 3 === 0 ? "Inpatient" : "Outpatient",
npi: `NPI${1000000000 + i}`,
service_category: `Service Category ${i % 4 === 0 ? "Surgery" : "Radiology"}`,
code: `CODE${2000 + i}`,
rate: Math.floor(Math.random() * 950 + 50) * 100,
yield: Math.floor(Math.random() * 900 + 50) * 95,
});
}
return data;
};

const rowDataScenario1 = ref(generateSampleData(10));
const rowDataScenario2 = ref(generateSampleData(30));
const rowDataScenario3 = ref(generateSampleData(195));

const rowData: RowDataFormat[] = [
{
provider_name: "Cherry Creek Hospital",
payer_name: "Aetna",
payer_type: "PPO",
payer_class: "Commercial",
provider_type: "Short Term Acute Care",
bill_type: "",
npi: "1234567890",
service_category: "OP Surgery",
code: "HCPCS 58353",
rate: 53800,
yield: 53800,
},
{
provider_name: "Cherry Creek Hospital",
payer_name: "Humana",
payer_type: "PPO",
payer_class: "Commercial",
provider_type: "Short Term Acute Care",
bill_type: "Inpatient",
npi: "56232367052",
service_category: "OP Surgery",
code: "HCPCS 64612",
rate: 5312,
yield: 5312,
},
{
provider_name: "Cherry Creek Hospital",
payer_name: "Blue Cross",
payer_type: "PPO",
payer_class: "Medicaid",
provider_type: "Rehabilitation",
bill_type: "Outpatient",
npi: "4159238584",
service_category: "OP Surgery",
code: "HCPCS 31641",
rate: 19482,
yield: 19482,
},
{
provider_name: "Cherry Creek Hospital",
payer_name: "Blue Cross",
payer_type: "HMO",
payer_class: "Commercial",
provider_type: "Rehabilitation",
bill_type: "Outpatient",
npi: "2236647281",
service_category: "OP Radiology",
code: "HCPCS 78601",
rate: 90699,
yield: 90699,
},
{
provider_name: "Banner Health",
payer_name: "Humana",
payer_type: "EPO",
payer_class: "Medicaid",
provider_type: "Long Term Acute Care",
bill_type: "Outpatient",
npi: "4200914767",
service_category: "OP Radiology",
code: "HCPCS 72050",
rate: 56023,
yield: 51234,
},
{
provider_name: "Cherry Creek Hospital",
payer_name: "Humana",
payer_type: "HMO",
payer_class: "Medicaid",
provider_type: "Long Term Acute Care",
bill_type: "Outpatient",
npi: "6021746420",
service_category: "OP Radiology",
code: "HCPCS 72255",
rate: 89361,
yield: 89361,
},
{
provider_name: "Cherry Creek Hospital",
payer_name: "Blue Cross",
payer_type: "EPO",
payer_class: "Medicaid",
provider_type: "Rehabilitation",
bill_type: "Inpatient",
npi: "4939467220",
service_category: "Cardiovascular",
code: "MSDRG 258",
rate: 791076,
yield: 791076,
},
{
provider_name: "Cherry Creek Hospital",
payer_name: "Cigna",
payer_type: "HMO",
payer_class: "Medicare",
provider_type: "Short Term Acute Care",
bill_type: "Outpatient",
npi: "6702380659",
service_category: "OP Surgery",
code: "HCPCS 72020",
rate: 65138,
yield: 65138,
},
{
provider_name: "Banner Health",
payer_name: "Blue Cross",
payer_type: "EPO",
payer_class: "Medicaid",
provider_type: "Rehabilitation",
bill_type: "Inpatient",
npi: "4548188898",
service_category: "Reproductive",
code: "MS-DRG 718",
rate: 43657,
yield: 43657,
},
{
provider_name: "Banner Health",
payer_name: "Humana",
payer_type: "PPO",
payer_class: "Medicaid",
provider_type: "Rehabilitation",
bill_type: "Inpatient",
npi: "4548188898",
service_category: "Reproductive",
code: "MS-DRG 749",
rate: 502023,
yield: 502023,
},
{
provider_name: "Cherry Creek Hospital",
payer_name: "Cigna",
payer_type: "EPO",
payer_class: "Commercial",
provider_type: "Long Term Acute Care",
bill_type: "Inpatient",
npi: "4882493334",
service_category: "Cardiovascular",
code: "MSDRG 235",
rate: 85038,
yield: 85038,
},
];
</script>

<template>
<div class="pv-container-lg">
<PvDataTable
:colDefs="colDefs"
:rowData="rowData"
:enableColumnVisibilitySelector="false"
:enableCsvExport="true"
:pagination="true"
:devMode="true"
:debugMode="true"
>
</PvDataTable>

<br /><br /><br />

<hr class="pv-hr pv-my-6" />
<!-- Added for separation -->
<h2>
Pagination Example: Less than one page of data (10 rows, page size 20)
</h2>
<PvDataTable
:colDefs="colDefs"
:rowData="rowDataScenario1"
:pagination="true"
:paginationPageSize="20"
:enableColumnVisibilitySelector="false"
:enableCsvExport="false"
:devMode="true"
:debugMode="true"
style="height: 350px"
>
</PvDataTable>

<br /><br />

<hr class="pv-hr pv-my-6" />
<!-- Added for separation -->
<h2>
Pagination Example: Approx 1.5 pages of data (30 rows, page size 20)
</h2>
<PvDataTable
:colDefs="colDefs"
:rowData="rowDataScenario2"
:pagination="true"
:paginationPageSize="20"
:enableColumnVisibilitySelector="false"
:enableCsvExport="false"
:devMode="true"
:debugMode="true"
style="height: 350px"
>
</PvDataTable>

<br /><br /><br /><br /><br />

<hr class="pv-hr pv-my-6" />
<!-- Added for separation -->
<h2>Pagination Example: 10 pages of data (95 rows, page size 20)</h2>
<PvDataTable
:colDefs="colDefs"
:rowData="rowDataScenario3"
:pagination="true"
:paginationPageSize="20"
:enableColumnVisibilitySelector="false"
:enableCsvExport="false"
:devMode="true"
:debugMode="true"
style="height: 450px"
>
</PvDataTable>
</div>

<br /><br /><br />
</template>

Properties

Event Name Type Description
column-moved ColumnMovedEvent<unknown, any> -
column-resized ColumnResizedEvent<unknown, any> -
column-row-group-changed ColumnRowGroupChangedEvent<unknown, any> -
grid-ready GridReadyEvent<unknown, any> -
filter-changed FilterChangedEvent<unknown, any> -
sort-changed SortChangedEvent<unknown, any> -
filter-opened FilterChangedEvent<unknown, any> -
first-data-rendered FirstDataRenderedEvent<unknown, any> -
handle-settings-icon string -