quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
1,209 lines (1,031 loc) • 32.3 kB
JavaScript
import { h, ref, computed, watch, getCurrentInstance } from 'vue'
import QTh from './QTh.js'
import QSeparator from '../separator/QSeparator.js'
import QIcon from '../icon/QIcon.js'
import QVirtualScroll from '../virtual-scroll/QVirtualScroll.js'
import QSelect from '../select/QSelect.js'
import QLinearProgress from '../linear-progress/QLinearProgress.js'
import QCheckbox from '../checkbox/QCheckbox.js'
import QBtn from '../btn/QBtn.js'
import getTableMiddle from './get-table-middle.js'
import useDark, {
useDarkProps
} from '../../composables/private.use-dark/use-dark.js'
import { commonVirtScrollPropsList } from '../virtual-scroll/use-virtual-scroll.js'
import useFullscreen, {
useFullscreenProps,
useFullscreenEmits
} from '../../composables/private.use-fullscreen/use-fullscreen.js'
import { useTableSort, useTableSortProps } from './table-sort.js'
import { useTableFilter, useTableFilterProps } from './table-filter.js'
import {
useTablePaginationState,
useTablePagination,
useTablePaginationProps
} from './table-pagination.js'
import {
useTableRowSelection,
useTableRowSelectionProps,
useTableRowSelectionEmits
} from './table-row-selection.js'
import {
useTableRowExpand,
useTableRowExpandProps,
useTableRowExpandEmits
} from './table-row-expand.js'
import {
useTableColumnSelection,
useTableColumnSelectionProps
} from './table-column-selection.js'
import {
injectProp,
injectMultipleProps
} from '../../utils/private.inject-obj-prop/inject-obj-prop.js'
import { createComponent } from '../../utils/private.create/create.js'
const bottomClass = 'q-table__bottom row items-center'
const virtScrollPassthroughProps = {}
commonVirtScrollPropsList.forEach(p => {
virtScrollPassthroughProps[p] = {}
})
export default createComponent({
name: 'QTable',
props: {
rows: {
type: Array,
required: true
},
rowKey: {
type: [String, Function],
default: 'id'
},
columns: Array,
loading: Boolean,
iconFirstPage: String,
iconPrevPage: String,
iconNextPage: String,
iconLastPage: String,
title: String,
hideHeader: Boolean,
grid: Boolean,
gridHeader: Boolean,
dense: Boolean,
flat: Boolean,
bordered: Boolean,
square: Boolean,
separator: {
type: String,
default: 'horizontal',
validator: v => ['horizontal', 'vertical', 'cell', 'none'].includes(v)
},
wrapCells: Boolean,
virtualScroll: Boolean,
virtualScrollTarget: {},
...virtScrollPassthroughProps,
noDataLabel: String,
noResultsLabel: String,
loadingLabel: String,
selectedRowsLabel: Function,
rowsPerPageLabel: String,
paginationLabel: Function,
color: {
type: String,
default: 'grey-8'
},
titleClass: [String, Array, Object],
tableStyle: [String, Array, Object],
tableClass: [String, Array, Object],
tableHeaderStyle: [String, Array, Object],
tableHeaderClass: [String, Array, Object],
tableRowStyleFn: Function,
tableRowClassFn: Function,
cardContainerClass: [String, Array, Object],
cardContainerStyle: [String, Array, Object],
cardStyle: [String, Array, Object],
cardClass: [String, Array, Object],
cardStyleFn: Function,
cardClassFn: Function,
hideBottom: Boolean,
hideSelectedBanner: Boolean,
hideNoData: Boolean,
hidePagination: Boolean,
onRowClick: Function,
onRowDblclick: Function,
onRowContextmenu: Function,
...useDarkProps,
...useFullscreenProps,
...useTableColumnSelectionProps,
...useTableFilterProps,
...useTablePaginationProps,
...useTableRowExpandProps,
...useTableRowSelectionProps,
...useTableSortProps
},
emits: [
'request',
'virtualScroll',
...useFullscreenEmits,
...useTableRowExpandEmits,
...useTableRowSelectionEmits
],
setup(props, { slots, emit }) {
const vm = getCurrentInstance()
const {
proxy: { $q }
} = vm
const isDark = useDark(props, $q)
const { inFullscreen, toggleFullscreen } = useFullscreen()
const getRowKey = computed(() =>
typeof props.rowKey === 'function'
? props.rowKey
: row => row[props.rowKey]
)
const rootRef = ref(null)
const virtScrollRef = ref(null)
const hasVirtScroll = computed(
() => props.grid !== true && props.virtualScroll === true
)
const cardDefaultClass = computed(
() =>
' q-table__card' +
(isDark.value === true ? ' q-table__card--dark q-dark' : '') +
(props.square === true ? ' q-table--square' : '') +
(props.flat === true ? ' q-table--flat' : '') +
(props.bordered === true ? ' q-table--bordered' : '')
)
const containerClass = computed(
() =>
`q-table__container q-table--${props.separator}-separator column no-wrap` +
(props.grid === true ? ' q-table--grid' : cardDefaultClass.value) +
(isDark.value === true ? ' q-table--dark' : '') +
(props.dense === true ? ' q-table--dense' : '') +
(props.wrapCells === false ? ' q-table--no-wrap' : '') +
(inFullscreen.value === true ? ' fullscreen scroll' : '')
)
const rootContainerClass = computed(
() =>
containerClass.value +
(props.loading === true ? ' q-table--loading' : '')
)
watch(
() =>
props.tableStyle +
props.tableClass +
props.tableHeaderStyle +
props.tableHeaderClass +
containerClass.value,
() => {
if (hasVirtScroll.value === true) virtScrollRef.value?.reset()
}
)
const {
innerPagination,
computedPagination,
isServerSide,
requestServerInteraction,
setPagination
} = useTablePaginationState(vm, getCellValue)
const { computedFilterMethod } = useTableFilter(props, setPagination)
const { isRowExpanded, setExpanded, updateExpanded } = useTableRowExpand(
props,
emit
)
const filteredSortedRows = computed(() => {
let rows = props.rows
if (isServerSide.value === true || rows.length === 0) {
return rows
}
const { sortBy, descending } = computedPagination.value
if (props.filter) {
rows = computedFilterMethod.value(
rows,
props.filter,
computedCols.value,
getCellValue
)
}
if (columnToSort.value !== null) {
rows = computedSortMethod.value(
props.rows === rows ? rows.slice() : rows,
sortBy,
descending
)
}
return rows
})
const filteredSortedRowsNumber = computed(
() => filteredSortedRows.value.length
)
const computedRows = computed(() => {
let rows = filteredSortedRows.value
if (isServerSide.value === true) {
return rows
}
const { rowsPerPage } = computedPagination.value
if (rowsPerPage !== 0) {
if (firstRowIndex.value === 0 && props.rows !== rows) {
if (rows.length > lastRowIndex.value) {
rows = rows.slice(0, lastRowIndex.value)
}
} else {
rows = rows.slice(firstRowIndex.value, lastRowIndex.value)
}
}
return rows
})
const {
hasSelectionMode,
singleSelection,
multipleSelection,
allRowsSelected,
someRowsSelected,
rowsSelectedNumber,
isRowSelected,
clearSelection,
updateSelection
} = useTableRowSelection(props, emit, computedRows, getRowKey)
const { colList, computedCols, computedColsMap, computedColspan } =
useTableColumnSelection(props, computedPagination, hasSelectionMode)
const { columnToSort, computedSortMethod, sort } = useTableSort(
props,
computedPagination,
colList,
setPagination
)
const {
firstRowIndex,
lastRowIndex,
isFirstPage,
isLastPage,
pagesNumber,
computedRowsPerPageOptions,
computedRowsNumber,
firstPage,
prevPage,
nextPage,
lastPage
} = useTablePagination(
vm,
innerPagination,
computedPagination,
isServerSide,
setPagination,
filteredSortedRowsNumber
)
const nothingToDisplay = computed(() => computedRows.value.length === 0)
const virtProps = computed(() => {
const acc = {}
commonVirtScrollPropsList.forEach(p => {
acc[p] = props[p]
})
if (acc.virtualScrollItemSize === void 0) {
acc.virtualScrollItemSize = props.dense === true ? 28 : 48
}
return acc
})
function resetVirtualScroll() {
if (hasVirtScroll.value === true) virtScrollRef.value.reset()
}
function getBody() {
if (props.grid === true) {
return getGridBody()
}
const header = props.hideHeader !== true ? getTHead : null
if (hasVirtScroll.value === true) {
const topRow = slots['top-row']
const bottomRow = slots['bottom-row']
const virtSlots = {
default: slotProps =>
getTBodyTR(slotProps.item, slots.body, slotProps.index)
}
if (topRow !== void 0) {
const topContent = h('tbody', topRow({ cols: computedCols.value }))
virtSlots.before =
header === null
? () => topContent
: () => [header()].concat(topContent)
} else if (header !== null) {
virtSlots.before = header
}
if (bottomRow !== void 0) {
virtSlots.after = () =>
h('tbody', bottomRow({ cols: computedCols.value }))
}
return h(
QVirtualScroll,
{
ref: virtScrollRef,
class: props.tableClass,
style: props.tableStyle,
...virtProps.value,
scrollTarget: props.virtualScrollTarget,
items: computedRows.value,
type: '__qtable',
tableColspan: computedColspan.value,
onVirtualScroll: onVScroll
},
virtSlots
)
}
const child = [getTBody()]
if (header !== null) {
child.unshift(header())
}
return getTableMiddle(
{
class: ['q-table__middle scroll', props.tableClass],
style: props.tableStyle
},
child
)
}
function scrollTo(toIndex, edge) {
if (virtScrollRef.value !== null) {
virtScrollRef.value.scrollTo(toIndex, edge)
return
}
toIndex = parseInt(toIndex, 10)
const rowEl = rootRef.value.querySelector(
`tbody tr:nth-of-type(${toIndex + 1})`
)
if (rowEl !== null) {
const scrollTarget = rootRef.value.querySelector(
'.q-table__middle.scroll'
)
const offsetTop = rowEl.offsetTop - props.virtualScrollStickySizeStart
const direction =
offsetTop < scrollTarget.scrollTop ? 'decrease' : 'increase'
scrollTarget.scrollTop = offsetTop
emit('virtualScroll', {
index: toIndex,
from: 0,
to: innerPagination.value.rowsPerPage - 1,
direction
})
}
}
function onVScroll(info) {
emit('virtualScroll', info)
}
function getProgress() {
return [
h(QLinearProgress, {
class: 'q-table__linear-progress',
color: props.color,
dark: isDark.value,
indeterminate: true,
trackColor: 'transparent'
})
]
}
function getTBodyTR(row, bodySlot, pageIndex) {
const key = getRowKey.value(row),
selected = isRowSelected(key)
if (bodySlot !== void 0) {
const cfg = {
key,
row,
pageIndex,
__trClass: selected ? 'selected' : ''
}
if (props.tableRowStyleFn !== void 0) {
cfg.__trStyle = props.tableRowStyleFn(row)
}
if (props.tableRowClassFn !== void 0) {
const cls = props.tableRowClassFn(row)
if (cls) {
cfg.__trClass = `${cls} ${cfg.__trClass}`
}
}
return bodySlot(getBodyScope(cfg))
}
const bodyCell = slots['body-cell'],
child = computedCols.value.map(col => {
const bodyCellCol = slots[`body-cell-${col.name}`],
slot = bodyCellCol !== void 0 ? bodyCellCol : bodyCell
return slot !== void 0
? slot(getBodyCellScope({ key, row, pageIndex, col }))
: h(
'td',
{
class: col.__tdClass(row),
style: col.__tdStyle(row)
},
getCellValue(col, row)
)
})
if (hasSelectionMode.value === true) {
const slot = slots['body-selection']
const content =
slot !== void 0
? slot(getBodySelectionScope({ key, row, pageIndex }))
: [
h(QCheckbox, {
modelValue: selected,
color: props.color,
dark: isDark.value,
dense: props.dense,
'onUpdate:modelValue': (adding, evt) => {
updateSelection([key], [row], adding, evt)
}
})
]
child.unshift(h('td', { class: 'q-table--col-auto-width' }, content))
}
const data = { key, class: { selected } }
if (props.onRowClick !== void 0) {
data.class['cursor-pointer'] = true
data.onClick = evt => {
emit('rowClick', evt, row, pageIndex)
}
}
if (props.onRowDblclick !== void 0) {
data.class['cursor-pointer'] = true
data.onDblclick = evt => {
emit('rowDblclick', evt, row, pageIndex)
}
}
if (props.onRowContextmenu !== void 0) {
data.class['cursor-pointer'] = true
data.onContextmenu = evt => {
emit('rowContextmenu', evt, row, pageIndex)
}
}
if (props.tableRowStyleFn !== void 0) {
data.style = props.tableRowStyleFn(row)
}
if (props.tableRowClassFn !== void 0) {
const cls = props.tableRowClassFn(row)
if (cls) {
data.class[cls] = true
}
}
return h('tr', data, child)
}
function getTBody() {
const body = slots.body,
topRow = slots['top-row'],
bottomRow = slots['bottom-row']
let child = computedRows.value.map((row, pageIndex) =>
getTBodyTR(row, body, pageIndex)
)
if (topRow !== void 0) {
child = topRow({ cols: computedCols.value }).concat(child)
}
if (bottomRow !== void 0) {
child = child.concat(bottomRow({ cols: computedCols.value }))
}
return h('tbody', child)
}
function getBodyScope(data) {
injectBodyCommonScope(data)
data.cols = data.cols.map(col =>
injectProp({ ...col }, 'value', () => getCellValue(col, data.row))
)
return data
}
function getBodyCellScope(data) {
injectBodyCommonScope(data)
injectProp(data, 'value', () => getCellValue(data.col, data.row))
return data
}
function getBodySelectionScope(data) {
injectBodyCommonScope(data)
return data
}
function injectBodyCommonScope(data) {
Object.assign(data, {
cols: computedCols.value,
colsMap: computedColsMap.value,
sort,
rowIndex: firstRowIndex.value + data.pageIndex,
color: props.color,
dark: isDark.value,
dense: props.dense
})
if (hasSelectionMode.value === true) {
injectProp(
data,
'selected',
() => isRowSelected(data.key),
(adding, evt) => {
updateSelection([data.key], [data.row], adding, evt)
}
)
}
injectProp(
data,
'expand',
() => isRowExpanded(data.key),
adding => {
updateExpanded(data.key, adding)
}
)
}
function getCellValue(col, row) {
const val =
typeof col.field === 'function' ? col.field(row) : row[col.field]
return col.format !== void 0 ? col.format(val, row) : val
}
const marginalsScope = computed(() => ({
pagination: computedPagination.value,
pagesNumber: pagesNumber.value,
isFirstPage: isFirstPage.value,
isLastPage: isLastPage.value,
firstPage,
prevPage,
nextPage,
lastPage,
inFullscreen: inFullscreen.value,
toggleFullscreen
}))
function getTopDiv() {
const top = slots.top,
topLeft = slots['top-left'],
topRight = slots['top-right'],
topSelection = slots['top-selection'],
hasSelection =
hasSelectionMode.value === true &&
topSelection !== void 0 &&
rowsSelectedNumber.value > 0,
topClass = 'q-table__top relative-position row items-center'
if (top !== void 0) {
return h('div', { class: topClass }, [top(marginalsScope.value)])
}
let child
if (hasSelection === true) {
child = topSelection(marginalsScope.value).slice()
} else {
child = []
if (topLeft !== void 0) {
child.push(
h('div', { class: 'q-table__control' }, [
topLeft(marginalsScope.value)
])
)
} else if (props.title) {
child.push(
h('div', { class: 'q-table__control' }, [
h(
'div',
{
class: ['q-table__title', props.titleClass]
},
props.title
)
])
)
}
}
if (topRight !== void 0) {
child.push(h('div', { class: 'q-table__separator col' }))
child.push(
h('div', { class: 'q-table__control' }, [
topRight(marginalsScope.value)
])
)
}
if (child.length === 0) return
return h('div', { class: topClass }, child)
}
const headerSelectedValue = computed(() =>
someRowsSelected.value === true ? null : allRowsSelected.value
)
function getTHead() {
const child = getTHeadTR()
if (props.loading === true && slots.loading === void 0) {
child.push(
h('tr', { class: 'q-table__progress' }, [
h(
'th',
{
class: 'relative-position',
colspan: computedColspan.value
},
getProgress()
)
])
)
}
return h('thead', child)
}
function getTHeadTR() {
const header = slots.header,
headerCell = slots['header-cell']
if (header !== void 0) {
return header(getHeaderScope({ header: true })).slice()
}
const child = computedCols.value.map(col => {
const headerCellCol = slots[`header-cell-${col.name}`],
slot = headerCellCol !== void 0 ? headerCellCol : headerCell,
slotProps = getHeaderScope({ col })
return slot !== void 0
? slot(slotProps)
: h(
QTh,
{
key: col.name,
props: slotProps
},
() => col.label
)
})
if (singleSelection.value === true && props.grid !== true) {
child.unshift(h('th', { class: 'q-table--col-auto-width' }, ' '))
} else if (multipleSelection.value === true) {
const slot = slots['header-selection']
const content =
slot !== void 0
? slot(getHeaderScope({}))
: [
h(QCheckbox, {
color: props.color,
modelValue: headerSelectedValue.value,
dark: isDark.value,
dense: props.dense,
'onUpdate:modelValue': onMultipleSelectionSet
})
]
child.unshift(h('th', { class: 'q-table--col-auto-width' }, content))
}
return [
h(
'tr',
{
class: props.tableHeaderClass,
style: props.tableHeaderStyle
},
child
)
]
}
function getHeaderScope(data) {
Object.assign(data, {
cols: computedCols.value,
sort,
colsMap: computedColsMap.value,
color: props.color,
dark: isDark.value,
dense: props.dense
})
if (multipleSelection.value === true) {
injectProp(
data,
'selected',
() => headerSelectedValue.value,
onMultipleSelectionSet
)
}
return data
}
function onMultipleSelectionSet(val) {
if (someRowsSelected.value === true) {
val = false
}
updateSelection(
computedRows.value.map(getRowKey.value),
computedRows.value,
val
)
}
const navIcon = computed(() => {
const ico = [
props.iconFirstPage || $q.iconSet.table.firstPage,
props.iconPrevPage || $q.iconSet.table.prevPage,
props.iconNextPage || $q.iconSet.table.nextPage,
props.iconLastPage || $q.iconSet.table.lastPage
]
return $q.lang.rtl === true ? ico.reverse() : ico
})
function getBottomDiv() {
if (props.hideBottom === true) return
if (nothingToDisplay.value === true) {
if (props.hideNoData === true) return
const message =
props.loading === true
? props.loadingLabel || $q.lang.table.loading
: props.filter
? props.noResultsLabel || $q.lang.table.noResults
: props.noDataLabel || $q.lang.table.noData
const noData = slots['no-data']
const children =
noData !== void 0
? [
noData({
message,
icon: $q.iconSet.table.warning,
filter: props.filter
})
]
: [
h(QIcon, {
class: 'q-table__bottom-nodata-icon',
name: $q.iconSet.table.warning
}),
message
]
return h(
'div',
{ class: bottomClass + ' q-table__bottom--nodata' },
children
)
}
const bottom = slots.bottom
if (bottom !== void 0) {
return h('div', { class: bottomClass }, [bottom(marginalsScope.value)])
}
const child =
props.hideSelectedBanner !== true &&
hasSelectionMode.value === true &&
rowsSelectedNumber.value > 0
? [
h('div', { class: 'q-table__control' }, [
h('div', [
(props.selectedRowsLabel || $q.lang.table.selectedRecords)(
rowsSelectedNumber.value
)
])
])
]
: []
if (props.hidePagination !== true) {
return h(
'div',
{
class: bottomClass + ' justify-end'
},
getPaginationDiv(child)
)
}
if (child.length !== 0) {
return h('div', { class: bottomClass }, child)
}
}
function onPagSelection(pag) {
setPagination({
page: 1,
rowsPerPage: pag.value
})
}
function getPaginationDiv(child) {
let control
const { rowsPerPage } = computedPagination.value,
paginationLabel = props.paginationLabel || $q.lang.table.pagination,
paginationSlot = slots.pagination,
hasOpts = props.rowsPerPageOptions.length > 1
child.push(h('div', { class: 'q-table__separator col' }))
if (hasOpts === true) {
child.push(
h('div', { class: 'q-table__control' }, [
h('span', { class: 'q-table__bottom-item' }, [
props.rowsPerPageLabel || $q.lang.table.recordsPerPage
]),
h(QSelect, {
class: 'q-table__select inline q-table__bottom-item',
color: props.color,
modelValue: rowsPerPage,
options: computedRowsPerPageOptions.value,
displayValue:
rowsPerPage === 0 ? $q.lang.table.allRows : rowsPerPage,
dark: isDark.value,
borderless: true,
dense: true,
optionsDense: true,
optionsCover: true,
'onUpdate:modelValue': onPagSelection
})
])
)
}
if (paginationSlot !== void 0) {
control = paginationSlot(marginalsScope.value)
} else {
control = [
h(
'span',
rowsPerPage !== 0 ? { class: 'q-table__bottom-item' } : {},
[
rowsPerPage
? paginationLabel(
firstRowIndex.value + 1,
Math.min(lastRowIndex.value, computedRowsNumber.value),
computedRowsNumber.value
)
: paginationLabel(
1,
filteredSortedRowsNumber.value,
computedRowsNumber.value
)
]
)
]
if (rowsPerPage !== 0 && pagesNumber.value > 1) {
const btnProps = {
color: props.color,
round: true,
dense: true,
flat: true
}
if (props.dense === true) {
btnProps.size = 'sm'
}
if (pagesNumber.value > 2) {
control.push(
h(QBtn, {
key: 'pgFirst',
...btnProps,
icon: navIcon.value[0],
disable: isFirstPage.value,
'aria-label': $q.lang.pagination.first,
onClick: firstPage
})
)
}
control.push(
h(QBtn, {
key: 'pgPrev',
...btnProps,
icon: navIcon.value[1],
disable: isFirstPage.value,
'aria-label': $q.lang.pagination.prev,
onClick: prevPage
}),
h(QBtn, {
key: 'pgNext',
...btnProps,
icon: navIcon.value[2],
disable: isLastPage.value,
'aria-label': $q.lang.pagination.next,
onClick: nextPage
})
)
if (pagesNumber.value > 2) {
control.push(
h(QBtn, {
key: 'pgLast',
...btnProps,
icon: navIcon.value[3],
disable: isLastPage.value,
'aria-label': $q.lang.pagination.last,
onClick: lastPage
})
)
}
}
}
child.push(h('div', { class: 'q-table__control' }, control))
return child
}
function getGridHeader() {
const child =
props.gridHeader === true
? [h('table', { class: 'q-table' }, [getTHead(h)])]
: props.loading === true && slots.loading === void 0
? getProgress(h)
: void 0
return h('div', { class: 'q-table__middle' }, child)
}
function getGridBody() {
const item =
slots.item !== void 0
? slots.item
: scope => {
const child = scope.cols.map(col =>
h('div', { class: 'q-table__grid-item-row' }, [
h('div', { class: 'q-table__grid-item-title' }, [col.label]),
h('div', { class: 'q-table__grid-item-value' }, [col.value])
])
)
if (hasSelectionMode.value === true) {
const slot = slots['body-selection']
const content =
slot !== void 0
? slot(scope)
: [
h(QCheckbox, {
modelValue: scope.selected,
color: props.color,
dark: isDark.value,
dense: props.dense,
'onUpdate:modelValue': (adding, evt) => {
updateSelection(
[scope.key],
[scope.row],
adding,
evt
)
}
})
]
child.unshift(
h('div', { class: 'q-table__grid-item-row' }, content),
h(QSeparator, { dark: isDark.value })
)
}
const data = {
class: [
'q-table__grid-item-card' + cardDefaultClass.value,
props.cardClass
],
style: props.cardStyle
}
if (props.cardStyleFn !== void 0) {
data.style = [data.style, props.cardStyleFn(scope.row)]
}
if (props.cardClassFn !== void 0) {
const cls = props.cardClassFn(scope.row)
if (cls) {
data.class[0] += ` ${cls}`
}
}
if (
props.onRowClick !== void 0 ||
props.onRowDblclick !== void 0 ||
props.onRowContextmenu !== void 0
) {
data.class[0] += ' cursor-pointer'
if (props.onRowClick !== void 0) {
data.onClick = evt => {
emit('RowClick', evt, scope.row, scope.pageIndex)
}
}
if (props.onRowDblclick !== void 0) {
data.onDblclick = evt => {
emit('RowDblclick', evt, scope.row, scope.pageIndex)
}
}
if (props.onRowContextmenu !== void 0) {
data.onContextmenu = evt => {
emit('rowContextmenu', evt, scope.row, scope.pageIndex)
}
}
}
return h(
'div',
{
class:
'q-table__grid-item col-xs-12 col-sm-6 col-md-4 col-lg-3' +
(scope.selected === true
? ' q-table__grid-item--selected'
: '')
},
[h('div', data, child)]
)
}
return h(
'div',
{
class: ['q-table__grid-content row', props.cardContainerClass],
style: props.cardContainerStyle
},
computedRows.value.map((row, pageIndex) =>
item(
getBodyScope({
key: getRowKey.value(row),
row,
pageIndex
})
)
)
)
}
// expose public methods and needed computed props
Object.assign(vm.proxy, {
requestServerInteraction,
setPagination,
firstPage,
prevPage,
nextPage,
lastPage,
isRowSelected,
clearSelection,
isRowExpanded,
setExpanded,
sort,
resetVirtualScroll,
scrollTo,
getCellValue
})
injectMultipleProps(vm.proxy, {
filteredSortedRows: () => filteredSortedRows.value,
computedRows: () => computedRows.value,
computedRowsNumber: () => computedRowsNumber.value
})
return () => {
const child = [getTopDiv()]
const data = { ref: rootRef, class: rootContainerClass.value }
if (props.grid === true) {
child.push(getGridHeader())
} else {
Object.assign(data, {
class: [data.class, props.cardClass],
style: props.cardStyle
})
}
child.push(getBody(), getBottomDiv())
if (props.loading === true && slots.loading !== void 0) {
child.push(slots.loading())
}
return h('div', data, child)
}
}
})