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 onlyagSetColumnFilter
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 |
- |