Appearance
ApiTable Component
The ApiTable
component is designed for displaying paginated API data. It leverages PrimeVue components (such as DataTable
, Paginator
, and Card
) to render a fully functional table with pagination support. By providing a listState instance, the component can manage data fetching, loading states, and pagination interactions automatically.
Component
vue
<template>
<div class="ui-api-table">
<Card class="ui-api-table__container-card">
<template #content>
<DataTable
class="ui-api-table__table"
:class="{ 'ui-api-table__table--clickable': props.clickable }"
:value="listState.list.value"
v-bind="$attrs"
:selection-mode="props.selectionMode"
@row-click="emit('row-click', $event)">
<slot></slot>
</DataTable>
<Paginator
class="mt-5"
:model-value="props.listState.pagination.value.current_page"
:rows="listState.pagination.value.per_page"
:total-records="props.listState.pagination.value.total"
@page="getList($event)"></Paginator>
</template>
</Card>
</div>
</template>
<script lang="ts">
import DataTable from 'primevue/datatable'
import Paginator from 'primevue/paginator'
import Card from 'primevue/card'
import type { Model as ModelType } from '@/helpers/models/Model'
export interface ApiTableInjectionType<
Api extends IApi<Model, ModelList>,
Model extends ModelType,
ModelList extends LaravelPaginationResponse<Model>,
> {
listState: ListState<Api, Model, ModelList> | undefined
selectable: boolean
selected: Set<Model>
isLoading: Ref<boolean>
selectionMode?: 'single' | 'multiple'
}
const injectionSymbol = Symbol('ApiTableInject')
export function createInjectionKey<
Api extends IApi<Model, ModelList>,
Model extends ModelType,
ModelList extends LaravelPaginationResponse<Model>,
>() {
return injectionSymbol as InjectionKey<ApiTableInjectionType<Api, Model, ModelList>>
}
</script>
<script
setup
lang="ts"
generic="
Api extends IApi<Model, ModelList>,
Model extends ModelType,
ModelList extends LaravelPaginationResponse<Model>
">
import {
defineProps,
computed,
defineEmits,
defineOptions,
type PropType,
type InjectionKey,
provide,
reactive,
type Ref,
} from 'vue'
import ListState from '@/helpers/models/ListState'
import type { IApi } from '@/helpers/models/Api'
import type { LaravelPaginationResponse } from '@/interfaces/models/Laravel'
defineOptions({
inheritAttrs: false,
})
const emit = defineEmits(['get-list', 'update:pagination-page', 'row-click'])
const props = defineProps({
listState: {
type: ListState<Api, Model, ModelList>,
required: true,
},
loading: {
type: Boolean,
required: false,
},
selectable: {
type: Boolean,
default: false,
},
selected: {
type: Set as PropType<Set<Model>>,
default: () => reactive(new Set()),
},
maxHeight: {
type: [Number, String],
default: 'auto',
},
selectionMode: {
type: String as PropType<'single' | 'multiple'>,
default: undefined,
},
clickable: {
type: Boolean,
default: false,
},
})
const isLoading = computed(() => {
return props.loading || !!props.listState?.isLoading.value
})
function getList(page: { page: number }) {
if (props.listState) {
props.listState.getList({ page: page.page + 1 })
}
emit('update:pagination-page', page.page + 1)
}
const injectionKey = createInjectionKey<Api, Model, ModelList>()
const providedData: ApiTableInjectionType<Api, Model, ModelList> = {
listState: props.listState,
selectable: props.selectable,
selected: props.selected,
isLoading: isLoading,
}
provide(injectionKey, providedData)
const maxHeightPx = computed(() => {
if (props.maxHeight === 'auto') {
return 'none'
}
return `${props.maxHeight}px`
})
</script>
Generic Parameters
Api
- Type:
IApi<Model, ModelList>
- Details The API instance used by the
ApiTable
must extend the generic API interface. It's type will be automatically inferred from thelistState
prop.
Model
- Type:
ModelType
- Details The model type representing the data item. It's type will be automatically inferred from the
listState
prop.
ModelList
- Type:
LaravelPaginationResponse<Model>
- Details The type representing the paginated response from the API. It's type will be automatically inferred from the
listState
prop.
Props
listState
- Type:
ListState<Api, Model, ModelList>
- Required:
true
- Details: The central state and methods for managing the list data and pagination. This is usually defined in the parent component and passed down to the
ApiTable
, allowing you to control the list of entities in the table from the parent component.
loading
- Type:
Boolean
- Required:
false
- Details: A boolean value indicating whether the table is in a loading state. When set to
true
, the table displays a loading spinner.
selectable
- Type:
Boolean
- Default:
false
- Details: A boolean value indicating whether the table rows are selectable. When set to
true
, the table displays checkboxes for selecting rows.
selected
- Type:
Set<Model>
- Default:
new Set()
- Details: A reactive set holding the selected items in the table. This prop is used to manage the selected items in the table and can be read or updated from the parent component.
maxHeight
- Type:
Number | String
- Default:
'auto'
- Details: The maximum height of the table. If set to
'auto'
, the table will expand to fit its content. Otherwise, the table will have a fixed height in px based on the provided numeric value. ThemaxHeight
is injected into the table's styles.
selectionMode
- Type:
'single' | 'multiple'
- Default:
undefined
- Details: The selection mode for the table rows. When set to
'single'
, only one row can be selected at a time. When set to'multiple'
, multiple rows can be selected.
clickable
- Type:
Boolean
- Default:
false
- Details: A boolean value indicating whether the table rows are clickable. When set to
true
, the rows will have a pointer cursor and emit arow-click
event when clicked.
Provide/Inject
The component uses an injection key to provide common state and methods to its child components (such as the ApiTableRemoveButton
component):
listState
- Type:
ListState<Api, Model, ModelList> | undefined
- Details: The central state and methods for managing the list data and pagination. This is usually defined in the parent component and passed down to the
ApiTable
, allowing you to control the list of entities in the table from the parent component.
selectable
- Type:
boolean
- Details: A boolean value indicating whether the table rows are selectable.
selected
- Type:
Set<Model>
- Details: A reactive set holding the selected items in the table.
isLoading
- Type:
Ref<boolean>
- Details: A reactive reference to a boolean value indicating whether the table is in a loading state.
Usage Example
The ApiTable
component is typically used in a few auto generated components.