Skip to content

Table Data

A table component that wraps KTableView with built-in data fetching functionality.

NOTE

If you are looking for a simpler table component that does not integrate data fetching, check out KTableView.

html
<KTableData
  :fetcher="fetcher"
  :headers="headers"
/>

Base KTableView Component

KTableData wraps the KTableView component, adding data fetching functionality.

KTableData supports all KTableView props, except for the data prop, which is replaced by the fetcher prop. It also supports slots and events, except for pagination events, which KTableData does not emit. Additionally, the headers prop and the update:table-preferences event are handled differently in KTableData. See the sections below for more details.

Props

headers

In addition to all header object properties supported by KTableView, KTableData also allows specifying whether a column should be sortable by providing a sortHandlerFunction prop.

ts
interface TableDataHeader {
  /** must be unique for each column, see Reserved Header Keys section for more information about 'actions' key value */
  key: string
  /** visible column header text */
  label: string
  /** this property defines whether sort icon should be displayed next to the column header and whether the column header will emit sort event upon clicking on it */
  sortable?: boolean
  /** allow toggling column visibility */
  hidable?: boolean
  /** when provided, an info icon will be rendered next to the column label, upon hovering on which the tooltip will be revealed */
  tooltip?: string
  /** whether column header text should be hidden (only visible to screen readers) */
  hideLabel?: boolean
  /** Whether KTableData should use function passed through sortHandlerFunction prop to apply sorting logic to this column */
  useSortHandlerFunction?: boolean
}

For an example of headers prop usage please refer to fetcher prop documentation below.

fetcher

Function that handles data fetching and pagination. It takes a single param as an argument which you can conveniently pass as a prop (see initialFetcherParams prop for details).

The fetcher function is expected to return an object with the following properties:

  • data - an array of objects to populate table with
  • total - the total count of items (if using pagination)
vue
<template>
  <KTableData
    :fetcher="fetcher"
    client-sort
    :headers="headers"
    :sort-handler-function="sortHandlerFunction"
  />
</template>

<script setup lang="ts">
import type { TableDataHeaders } from '@kong/kongponents'

const headers: TableDataHeaders = [
  { key: 'name', label: 'Full Name' },
  {
    key: 'username',
    label: 'Username',
    sortable: true,
    tooltip: 'Unique for each user.',
    useSortHandlerFunction: true
  },
  {
    key: 'email',
    label: 'Email',
    hidable: true
  },
]

const fetcher = async (): Promise<any> => {
  // Fake delay
  await new Promise((resolve) => setTimeout(resolve, 2000))

  const responseData = [
    {
      id: 1,
      // notice that property keys in data object correspond to each respective key in headers const
      name: 'Leanne Graham', 
      username: 'Bret',
      email: 'Sincere@april.biz'
    },
    {
      id: 2,
      name: 'Ervin Howell',
      username: 'Antonette',
      email: 'Shanna@melissa.tv'
    },
    ...
  ]

  return {
    data: responseData,
    total: responseData.length,
  }
}

const sortHandlerFunction = ({ key, sortColumnOrder, data }) => {
  return data.sort((a, b) => {
    if (key === 'username') {
      if (sortColumnOrder === 'asc') {
        if (a.username > b.username) {
          return 1
        } else if (a.username < b.username) {
          return -1
        }

        return 0
      } else {
        if (a.username > b.username) {
          return -1
        } else if (a.username < b.username) {
          return 1
        }

        return 0
      }
    }

    return data
  })
}
</script>

NOTE

Notice in the example above the Username column is sortable. In this example sorting is handled client-side; however, should you want to handle sorting differently (e.g. make a call to the back-end to apply server-side logic), you can bind your logic to the sort event and perform re-fetching of data as needed.

initialFetcherParams

The fetcher function accepts a single parameter, an object with the following properties:

ts
interface TableDataFetcherParams {
  /**
   * The number of items to display per page.
   */
  pageSize?: number
  /**
   * The currently active page.
   */
  page?: number
  /**
   * A text string to filter table data on (defined in the searchInput prop).
   */
  query?: string
  /**
   * Sortable column key (defined in the headers prop).
   */
  sortColumnKey?: string
  /**
   * Sorting order.
   */
  sortColumnOrder?: 'asc' | 'desc'
  /**
   * The value of the offset for offset-based pagination. Offset must be included in the fetcher params for offset-based pagination to work properly.
   */
  offset?: string | null
}

For ease of configuration, all properties in the initialFetcherParams object have default fallback values:

ts
{ 
  pageSize: 15,
  page: 1,
  query: '',
  sortColumnKey: '',
  sortColumnOrder: '',
  offset: null
}

clientSort

Boolean to enable client-side sorting if using a fetcher that returns unpaginated data. Defaults to false. Use this in conjunction with sortHandlerFunction prop.

sortHandlerFunction

Pass a custom sort handler function to handle sorting table data for specific columns.

WARNING

If clientSort prop is true but no sortHandlerFunction provided, KTableData will apply some default logic for client side sorting. This may produce unexpected results. We recommend always providing a sortHandlerFunction when using client-side sorting.

The function can take an object with these properties as the only argument and should return sorted array of table record objects:

ts
interface SortHandlerFunctionParam {
  /** The key of the column to be sorted */
  key: string
  /** The key of the column previously sorted */
  prevKey: string
  /** The order in which to sort the column (asc or desc) */
  sortColumnOrder: 'asc' | 'desc'
  /** The data returned from the fetcher function response */
  data: Array<any>
}

NOTE

Please note that you have to set clientSort prop to true as well as to pass sortable: true and useSortHandlerFunction: true in the respective headers object to make a column sortable via sortHandlerFunction.

Please refer to the fetcher prop documentation for an example.

cacheIdentifier

The fetcher functionality makes use of SWRV to handle caching of response data. In order to take advantage of this caching, SWRV needs a way to identify which cache entry is associated with the table.

The identifier should be a string and will default to '' if not provided. In that scenario, we will generate a random ID for the identifier every time the table is mounted.

DANGER

This identifier must be unique across all KTableData instances across the entire Vue app, otherwise there is a risk that SWRV will return the cached data of the wrong table.

fetcherCacheKey

Whenever the cache key is changed the fetcher will automatically be called and attempt to fetch new table data.

vue
<template>
  <KTableData
    cache-identifier="fetcher-cache-key-example-table"
    :fetcher-cache-key="String(cacheKey)"
    :fetcher="fetcher"
    :headers="headers"
  />
</template>

<script setup lang="ts">
const cacheKey = ref<number>(1)

const itemDeleted = (): void => {
  cacheKey.value++ // triggers refetch or reactivity
}
</script>

An alternate implementation is to apply a key attribute to the KTableData in conjunction with a fetcher and the SWRV revalidate function. To prevent unnecessary calls on mount, the key ref should have an initial value of 0.

Since the fetcher function will handle the initial fetch of the data, we want the cache key for the revalidate function to be a falsey value on page load (to avoid an unnecessary duplicate call), and will manually call revalidate() and increment the key to trigger a refetch and redraw of the table.

html
<template>
  <KTableData :key="key" :fetcher="fetcher" :headers="headers" />
</template>

<script setup lang="ts">
const key = ref<string>(0) // initialized to zero

const fetcher = async ({ pageSize, page, query, offset = null }) => {
  try {
    const res = await services.getAll(pageSize, offset)

    // handle data
  } catch (error) {
    // handle error
  }
}

const { revalidate } = composables.useRequest(
  () => key.value && `service-list-${key.value}`, // will evaluate to falsey on mount, preventing an extra call
  () => { return fetcher() }
)

const handleDelete = (id): void => {
  try {
    const res = await services.delete(id)

    key.value++
    revalidate()
  } catch (error) {
    // handle error
  }
}
</script>

searchInput

A string that will passed to fetcher function and can be used to modify the API request to perform data filtering.

sortable

Set this to false to disable ability to sort.

Events

state

Fired when the table state changes. Returns an object of type TableStatePayload:

ts
interface TableStatePayload {
  state: TableState
  hasData: boolean
}

type TableState = 'loading' | 'error' | 'success' | 'empty'

update:table-preferences

This event only fires when KTableData is in success state (see state event for details).

Released under the Apache-2.0 License.