LinkDesk/frontend/docs/shots-datatable-checkbox-fi...

3.6 KiB

ShotsDataTable Checkbox Selection Fix

Issue

The shot table multi-selection wasn't working. Investigation revealed that the actual component being used is ShotsDataTable.vue (not ShotsTableView.vue), which uses TanStack Table with render functions.

Root Cause

The checkbox columns in columns.ts were using the wrong event binding:

  • Used: 'onUpdate:checked'
  • Should use: 'onUpdate:modelValue' (for v-model binding in render functions)

Additionally, the value parameter type needed to handle both boolean and 'indeterminate' values.

Fix Applied

File: frontend/src/components/shot/columns.ts

Before:

header: ({ table }) =>
  h(Checkbox, {
    checked: table.getIsAllPageRowsSelected(),
    indeterminate: table.getIsSomePageRowsSelected(),
    'onUpdate:checked': (value: boolean) => table.toggleAllPageRowsSelected(!!value),
    ariaLabel: 'Select all',
  }),
cell: ({ row }) =>
  h(Checkbox, {
    checked: row.getIsSelected(),
    'onUpdate:checked': (value: boolean) => row.toggleSelected(!!value),
    ariaLabel: 'Select row',
    onClick: (e: Event) => e.stopPropagation(),
  }),

After:

header: ({ table }) =>
  h(Checkbox, {
    modelValue: table.getIsAllPageRowsSelected(),
    'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(value === true),
    ariaLabel: 'Select all',
  }),
cell: ({ row }) =>
  h(Checkbox, {
    modelValue: row.getIsSelected(),
    'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(value === true),
    ariaLabel: 'Select row',
    onClick: (e: Event) => e.stopPropagation(),
  }),

Key Changes

  1. Event Binding: Changed from 'onUpdate:checked' to 'onUpdate:modelValue'

    • When using h() render function, v-model binds to modelValue prop and onUpdate:modelValue event
  2. Prop Binding: Changed from checked to modelValue

    • Matches the v-model convention for render functions
  3. Type Handling: Updated value parameter type to boolean | 'indeterminate'

    • Checkbox component can emit 'indeterminate' state
    • Convert to boolean with value === true before passing to TanStack Table
  4. Removed Indeterminate Prop: No longer needed as separate prop

    • TanStack Table's getIsSomePageRowsSelected() is handled internally

Why This Works

When using Vue's h() render function to create components:

  • v-model translates to modelValue prop + onUpdate:modelValue event
  • This is different from template syntax where you can use v-model directly
  • The Checkbox component from shadcn-vue/reka-ui expects this pattern

Testing

Test the following scenarios:

  1. Click individual checkboxes to select/deselect shots
  2. Click the header checkbox to select all shots
  3. Click the header checkbox again to deselect all shots
  4. Select some shots, verify header shows indeterminate state
  5. With some selected, click header to select all
  6. Verify row highlighting reflects selection state
  7. Verify TanStack Table's selection state is properly maintained
  • frontend/src/components/shot/columns.ts - Fixed checkbox column definitions
  • frontend/src/components/shot/ShotsDataTable.vue - Table component using the columns
  • frontend/src/components/shot/ShotBrowser.vue - Parent component that uses ShotsDataTable

Notes

  • ShotsTableView.vue exists but is NOT currently being used in the application
  • The actual table implementation uses TanStack Table via ShotsDataTable.vue
  • This fix is specific to render function usage with TanStack Table