Advanced

Events

Handle NuGrid events for user interactions.

NuGrid emits events for various user interactions, allowing you to respond to clicks, edits, navigation, and state changes.

Event Categories

Click Events

EventPayloadDescription
cell-clickedNuGridCellClickEventCell was clicked
cell-double-clickedNuGridCellClickEventCell was double-clicked
row-clickedNuGridRowClickEventRow was clicked
row-double-clickedNuGridRowClickEventRow was double-clicked

Focus Events

EventPayloadDescription
focused-cell-changedNuGridFocusedCellChangedEventFocused cell changed
focused-row-changedNuGridFocusedRowChangedEventFocused row changed

Editing Events

EventPayloadDescription
cell-editing-startedNuGridCellEditingStartedEventCell editing began
cell-editing-cancelledNuGridCellEditingCancelledEventCell editing was cancelled
cell-value-changedNuGridCellValueChangedEventCell value was saved

State Events

EventPayloadDescription
sort-changedNuGridSortChangedEventSorting changed
filter-changedNuGridFilterChangedEventFilters changed
row-selection-changedRecord<string, boolean>Selection changed

Row Events

EventPayloadDescription
row-add-requestedRow dataNew row submitted
row-draggedDrag eventRow was reordered

Click Events

Cell Click

<script setup lang="ts">
import type { NuGridCellClickEvent } from '#nu-grid/types'

function onCellClicked(event: NuGridCellClickEvent<User>) {
  console.log('Cell clicked:', {
    row: event.row.original,
    column: event.column.id,
    value: event.value,
  })
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    @cell-clicked="onCellClicked"
  />
</template>

Cell Double Click

<script setup lang="ts">
function onCellDoubleClicked(event) {
  // Navigate to detail page on double-click
  navigateTo(`/users/${event.row.original.id}`)
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    @cell-double-clicked="onCellDoubleClicked"
  />
</template>

Row Click

<script setup lang="ts">
function onRowClicked(event) {
  // Select row on click
  selectedUserId.value = event.row.original.id
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    @row-clicked="onRowClicked"
  />
</template>

Focus Events

Focused Cell Changed

<script setup lang="ts">
import type { NuGridFocusedCellChangedEvent } from '#nu-grid/types'

function onFocusedCellChanged(event: NuGridFocusedCellChangedEvent<User>) {
  console.log('Focus moved:', {
    from: `${event.previousRowIndex}:${event.previousColumnIndex}`,
    to: `${event.rowIndex}:${event.columnIndex}`,
    rowId: event.rowId,
    columnId: event.columnId,
  })
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :focus="{ mode: 'cell' }"
    @focused-cell-changed="onFocusedCellChanged"
  />
</template>

Focused Row Changed

<script setup lang="ts">
function onFocusedRowChanged(event) {
  // Load details for focused row
  loadUserDetails(event.rowId)
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :focus="{ mode: 'row' }"
    @focused-row-changed="onFocusedRowChanged"
  />
</template>

Editing Events

Cell Editing Started

<script setup lang="ts">
function onCellEditingStarted(event) {
  console.log('Started editing:', event.column.id, 'value:', event.value)

  // Prevent editing for locked rows
  if (event.row.original.locked) {
    return false  // Cancels the edit
  }
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :editing="{ enabled: true }"
    @cell-editing-started="onCellEditingStarted"
  />
</template>

Cell Value Changed

<script setup lang="ts">
async function onCellValueChanged(event) {
  console.log('Value changed:', {
    column: event.column.id,
    oldValue: event.oldValue,
    newValue: event.newValue,
  })

  // Persist to server
  try {
    await api.updateUser(event.row.original.id, {
      [event.column.id]: event.newValue,
    })
    toast.add({ title: 'Saved', color: 'success' })
  } catch (error) {
    toast.add({ title: 'Failed to save', color: 'error' })
    // Optionally revert
    event.row.original[event.column.id] = event.oldValue
  }
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :editing="{ enabled: true }"
    @cell-value-changed="onCellValueChanged"
  />
</template>

Cell Editing Cancelled

<script setup lang="ts">
function onCellEditingCancelled(event) {
  console.log('Editing cancelled:', event.column.id)
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :editing="{ enabled: true }"
    @cell-editing-cancelled="onCellEditingCancelled"
  />
</template>

State Events

Sort Changed

<script setup lang="ts">
function onSortChanged(event) {
  console.log('Sorting:', event.sorting)
  // [{ id: 'name', desc: false }, ...]
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    @sort-changed="onSortChanged"
  />
</template>

Filter Changed

<script setup lang="ts">
function onFilterChanged(event) {
  console.log('Filters:', event.columnFilters)
  // [{ id: 'status', value: 'active' }, ...]
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    @filter-changed="onFilterChanged"
  />
</template>

Row Selection Changed

<script setup lang="ts">
function onRowSelectionChanged(selection: Record<string, boolean>) {
  const selectedIds = Object.entries(selection)
    .filter(([, selected]) => selected)
    .map(([id]) => id)

  console.log('Selected:', selectedIds)
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    selection="multi"
    @row-selection-changed="onRowSelectionChanged"
  />
</template>

Example: Event Logger

<script setup lang="ts">
interface LogEntry {
  id: number
  event: string
  time: string
  payload: string
}

const log = ref<LogEntry[]>([])
let counter = 0

function logEvent(name: string, payload: any) {
  log.value.unshift({
    id: ++counter,
    event: name,
    time: new Date().toLocaleTimeString(),
    payload: JSON.stringify(payload, null, 2),
  })

  if (log.value.length > 50) {
    log.value.pop()
  }
}
</script>

<template>
  <div class="flex gap-4">
    <NuGrid
      :data="data"
      :columns="columns"
      :editing="{ enabled: true }"
      :focus="{ mode: 'cell' }"
      selection="multi"
      class="flex-1"
      @cell-clicked="e => logEvent('cell-clicked', { row: e.row.id, col: e.column.id })"
      @cell-double-clicked="e => logEvent('cell-double-clicked', { row: e.row.id, col: e.column.id })"
      @focused-cell-changed="e => logEvent('focused-cell-changed', { row: e.rowIndex, col: e.columnIndex })"
      @cell-editing-started="e => logEvent('cell-editing-started', { col: e.column.id })"
      @cell-value-changed="e => logEvent('cell-value-changed', { old: e.oldValue, new: e.newValue })"
      @sort-changed="e => logEvent('sort-changed', e.sorting)"
      @row-selection-changed="e => logEvent('row-selection-changed', Object.keys(e).length)"
    />

    <div class="w-80 rounded-lg border p-4">
      <h3 class="mb-2 font-semibold">Event Log</h3>
      <div class="max-h-96 space-y-2 overflow-auto text-xs">
        <div v-for="entry in log" :key="entry.id" class="rounded bg-gray-50 p-2 dark:bg-gray-800">
          <div class="flex justify-between">
            <span class="font-medium text-primary">{{ entry.event }}</span>
            <span class="text-gray-400">{{ entry.time }}</span>
          </div>
          <pre class="mt-1 text-gray-600 dark:text-gray-400">{{ entry.payload }}</pre>
        </div>
      </div>
    </div>
  </div>
</template>

Next Steps

Row Actions

Add action menus to rows.

Excel Export

Export data to Excel.