Skip to content

Commit

Permalink
docs: Vue example - Row Selection (#5158)
Browse files Browse the repository at this point in the history
* Clone basic example

Signed-off-by: Phillip Rak <rak.phillip@gmail.com>

* Create basic row selection example

Signed-off-by: Phillip Rak <rak.phillip@gmail.com>

* Generate example table data

Signed-off-by: Phillip Rak <rak.phillip@gmail.com>

---------

Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
  • Loading branch information
rak-phillip committed Dec 17, 2023
1 parent cc8ecd9 commit b91fe9a
Show file tree
Hide file tree
Showing 15 changed files with 1,331 additions and 0 deletions.
24 changes: 24 additions & 0 deletions examples/vue/row-selection/.gitignore
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
6 changes: 6 additions & 0 deletions examples/vue/row-selection/README.md
@@ -0,0 +1,6 @@
# Example

To run this example:

- `npm install` or `yarn`
- `npm run dev` or `yarn dev`
1 change: 1 addition & 0 deletions examples/vue/row-selection/env.d.ts
@@ -0,0 +1 @@
/// <reference types="vite/client" />
14 changes: 14 additions & 0 deletions examples/vue/row-selection/index.html
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
22 changes: 22 additions & 0 deletions examples/vue/row-selection/package.json
@@ -0,0 +1,22 @@
{
"name": "tanstack-table-example-vue-row-selection",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.2.33",
"@tanstack/vue-table": "8.10.7"
},
"devDependencies": {
"@types/node": "^16.11.27",
"@vitejs/plugin-vue": "^4.4.0",
"@vitejs/plugin-vue-jsx": "^3.0.2",
"typescript": "^4.9.5",
"vite": "^4.4.11",
"vue-tsc": "^1.8.19"
}
}
Binary file added examples/vue/row-selection/public/favicon.ico
Binary file not shown.
188 changes: 188 additions & 0 deletions examples/vue/row-selection/src/App.vue
@@ -0,0 +1,188 @@
<script setup lang="tsx">
import {
FlexRender,
getCoreRowModel,
getPaginationRowModel,
useVueTable,
createColumnHelper,
RowSelectionState,
} from '@tanstack/vue-table'
import { ref } from 'vue'
import IndeterminateCheckbox from './IndeterminateCheckbox.vue';
import { makeData, Person } from './makeData'
const columnHelper = createColumnHelper<Person>()
const columns = [
{
id: 'select',
header: ({ table }: { table: any }) => {
return <IndeterminateCheckbox
checked={table.getIsAllRowsSelected()}
indeterminate={table.getIsSomeRowsSelected()}
onChange={table.getToggleAllRowsSelectedHandler()}
></IndeterminateCheckbox>
},
cell: ({ row }: { row: any }) => {
return <div className="px-1">
<IndeterminateCheckbox
checked={row.getIsSelected()}
disabled={!row.getCanSelect()}
onChange={row.getToggleSelectedHandler()}
></IndeterminateCheckbox>
</div>
}
},
columnHelper.group({
header: 'Name',
footer: props => props.column.id,
columns: [
columnHelper.accessor('firstName', {
cell: info => info.getValue(),
footer: props => props.column.id,
}),
columnHelper.accessor(row => row.lastName, {
id: 'lastName',
cell: info => info.getValue(),
header: () => 'Last Name',
footer: props => props.column.id,
}),
],
}),
columnHelper.group({
header: 'Info',
footer: props => props.column.id,
columns: [
columnHelper.accessor('age', {
header: () => 'Age',
footer: props => props.column.id,
}),
columnHelper.group({
header: 'More Info',
columns: [
columnHelper.accessor('visits', {
header: () => 'Visits',
footer: props => props.column.id,
}),
columnHelper.accessor('status', {
header: 'Status',
footer: props => props.column.id,
}),
columnHelper.accessor('progress', {
header: 'Profile Progress',
footer: props => props.column.id,
}),
],
}),
],
}),
]
const data = ref(makeData(10))
const rowSelection = ref<RowSelectionState>({})
const rerender = () => {
data.value = makeData(10)
}
const table = useVueTable({
get data() {
return data.value
},
columns,
state: {
get rowSelection() {
return rowSelection.value
},
},
enableRowSelection: true, //enable row selection for all rows
// enableRowSelection: row => row.original.age > 18, // or enable row selection conditionally per row
onRowSelectionChange: updateOrValue => {
rowSelection.value =
typeof updateOrValue === 'function'
? updateOrValue(rowSelection.value)
: updateOrValue;
},
getCoreRowModel: getCoreRowModel(),
})
</script>
<template>
<div class="p-2">
<table>
<thead>
<tr
v-for="headerGroup in table.getHeaderGroups()"
:key="headerGroup.id"
>
<th
v-for="header in headerGroup.headers"
:key="header.id"
:colSpan="header.colSpan"
>
<FlexRender
v-if="!header.isPlaceholder"
:render="header.column.columnDef.header"
:props="header.getContext()"
/>
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in table.getRowModel().rows" :key="row.id">
<td v-for="cell in row.getVisibleCells()" :key="cell.id">
<FlexRender
:render="cell.column.columnDef.cell"
:props="cell.getContext()"
/>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td className="p-1">
<IndeterminateCheckbox
:checked="table.getIsAllPageRowsSelected()"
:indeterminate="table.getIsSomePageRowsSelected()"
:onChange="table.getToggleAllPageRowsSelectedHandler()"
/>
</td>
<td :colSpan="20">Page Rows {{ table.getRowModel().rows.length }}</td>
</tr>
</tfoot>
</table>
<div class="h-4" />
<button @click="rerender" class="border p-2">Rerender</button>
</div>
</template>
<style>
html {
font-family: sans-serif;
font-size: 14px;
}
table {
border: 1px solid lightgray;
}
tbody {
border-bottom: 1px solid lightgray;
}
th {
border-bottom: 1px solid lightgray;
border-right: 1px solid lightgray;
padding: 2px 4px;
}
tfoot {
color: gray;
}
tfoot th {
font-weight: normal;
}
</style>
22 changes: 22 additions & 0 deletions examples/vue/row-selection/src/IndeterminateCheckbox.vue
@@ -0,0 +1,22 @@
<script setup lang="ts">
import { ref, onMounted, useAttrs, toRefs } from 'vue';
const props = defineProps<{
indeterminate: boolean,
className?: string,
}>();
const { indeterminate, className } = toRefs(props);
const inputRef = ref<any>(null);
</script>

<template>
<input
type="checkbox"
ref="inputRef"
:class="`${className} cursor-pointer`"
:indeterminate="indeterminate"
v-bind="$attrs"
/>
</template>
8 changes: 8 additions & 0 deletions examples/vue/row-selection/src/env.d.ts
@@ -0,0 +1,8 @@
/// <reference types="vite/client" />

declare module '*.vue' {
import type { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}
4 changes: 4 additions & 0 deletions examples/vue/row-selection/src/main.ts
@@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')
48 changes: 48 additions & 0 deletions examples/vue/row-selection/src/makeData.ts
@@ -0,0 +1,48 @@
import { faker } from '@faker-js/faker'

export type Person = {
firstName: string
lastName: string
age: number
visits: number
progress: number
status: 'relationship' | 'complicated' | 'single'
subRows?: Person[]
}

const range = (len: number) => {
const arr = []
for (let i = 0; i < len; i++) {
arr.push(i)
}
return arr
}

const newPerson = (): Person => {
return {
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
age: faker.number.int(40),
visits: faker.number.int(1000),
progress: faker.number.int(100),
status: faker.helpers.shuffle<Person['status']>([
'relationship',
'complicated',
'single',
])[0]!,
}
}

export function makeData(...lens: number[]) {
const makeDataLevel = (depth = 0): Person[] => {
const len = lens[depth]!
return range(len).map((d): Person => {
return {
...newPerson(),
subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
}
})
}

return makeDataLevel()
}
35 changes: 35 additions & 0 deletions examples/vue/row-selection/tsconfig.dev.json
@@ -0,0 +1,35 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./build/types",
"types": [
"vite/client"
]
},
"files": [
"src/main.ts"
],
"include": [
"src"
// "__tests__/**/*.test.*"
]
}
// {
// "composite": true,
// "compilerOptions": {
// "target": "esnext",
// "useDefineForClassFields": true,
// "module": "esnext",
// "moduleResolution": "node",
// "strict": true,
// "jsx": "preserve",
// "sourceMap": true,
// "resolveJsonModule": true,
// "isolatedModules": true,
// "esModuleInterop": true,
// "lib": ["esnext", "dom"],
// "skipLibCheck": true
// },
// "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
// "references": [{ "path": "./tsconfig.node.json" }]
// }
8 changes: 8 additions & 0 deletions examples/vue/row-selection/tsconfig.node.json
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"composite": true,
"module": "esnext",
"moduleResolution": "node"
},
"include": ["vite.config.ts"]
}

0 comments on commit b91fe9a

Please sign in to comment.