Files
oa/documentation/flex-table/v-flex-table-with-slots-documentation.md
2025-05-24 01:49:48 +09:00

4.5 KiB

example_bottom
example_bottom
true

Make VFlexTable yours with slots

The easiest way to create complex tables with <VFlexTable /> is to uses slots. This allow to use other components and having great control inside rows (with #body-cell slot) and columns (with #header-column slot). To update data dynamically, use reactive props so your interface will know that data is updated, this is disabled by default to prevent performance issues.
Check the markup for more details about usage.

<script setup lang="ts">
const selectedRowsId = ref<number[]>([])
const editCompanyIndex = ref<number>()

const isAllSelected = computed(
  () => flexRowsContacts.length === selectedRowsId.value.length,
)

// this is our data
const data = [
  {
    id: 0,
    company: 'Grubspot',
    type: 'New Lead',
    industry: 'Software',
    status: 'Active',
    contacts: [
      {
        id: 0,
        picture: 'https://media.cssninja.io/content/avatars/25.jpg',
        initials: 'AC',
        color: 'info',
      },
      // and more contacts ..
    ],
  },
  // and more data ...
]

// this is the columns configuration
const columns = {
  select: {
    label: '',
    cellClass: 'is-flex-grow-0',
  },
  company: {
    label: 'Company',
    grow: true,
  },
  type: 'Type',
  industry: 'Industry',
  status: 'Status',
  contacts: {
    label: 'Contacts',
    align: 'end',
  },
}

// the select all checkbox click handler
function toggleSelection() {
  if (isAllSelected.value) {
    selectedRowsId.value = []
  }
  else {
    selectedRowsId.value = flexRowsContacts.map((_, index) => index)
  }
}
// this it the row click handler (enabled with clickable props)
function clickOnRow(row: any) {
  if (selectedRowsId.value.includes(row.id)) {
    selectedRowsId.value = selectedRowsId.value.filter(i => i !== row.id)
  }
  else {
    selectedRowsId.value = [...selectedRowsId.value, row.id]
  }
}

// this is the "Contact me" click handler
function contactUser(row: any) {
  alert(`Contacting "${row.company}" ...`)
}

// this is a local directive (it begins with V..., usable with v-focus)
// that is used to force the focus on input when mounted
const VFocus = {
  mounted(el: HTMLInputElement) {
    el.focus()
  },
}
</script>

<template>
  <VFlexTable
    :data="data"
    :columns="columns"
    clickable
    compact
    rounded
    @row-click="clickOnRow"
  >
    <!-- header-column slot -->
    <template #header-column="{ column }">
      <VCheckbox
        v-if="column.key === 'select'"
        class="ml-2 mr-3"
        :checked="isAllSelected"
        name="all_selected"
        color="primary"
        square
        @click="toggleSelection"
      />
    </template>

    <!-- body-cell slot -->
    <template #body-cell="{ row, column, value }">
      <!--This is the slot for row.select cells-->
      <VCheckbox
        v-if="column.key === 'select'"
        v-model="selectedRowsId"
        :value="row.id"
        name="selection"
        square
      />

      <!--This is the slot for row.company cells-->
      <template v-else-if="column.key === 'company'">
        <VControl v-if="editCompanyIndex === index">
          <VField>
            <input
              v-model="row[column.key]"
              v-focus
              type="text"
              class="input is-primary-focus"
              @blur="editCompanyIndex = undefined"
              @keydown.enter="editCompanyIndex = undefined"
            >
          </VField>
        </VControl>

        <a
          v-else
          class="is-overlay m-3 is-flex is-align-items-center is-clickable edit-icon-link"
          role="button"
          tabindex="0"
          @click="editCompanyIndex = index"
          @keydown.enter="editCompanyIndex = index"
        >
          {{ value }}
          <VIcon
            class="is-inline ml-1"
            icon="lucide:edit"
            role="img"
            aria-label="edit-3"
          />
        </a>
      </template>

      <!--This is the slot for row.status cells-->
      <VTag
        v-else-if="column.key === 'status'"
        rounded
        :color="
          value === 'Suspended'
            ? 'orange'
            : value === 'New'
              ? 'info'
              : value === 'Active'
                ? 'primary'
                : undefined
        "
      >
        {{ value }}
      </VTag>

      <!--This is the slot for row.contacts cells-->
      <VAction v-if="column.key === 'contacts'" @click.stop="contactUser(row)">
        Contact me
      </VAction>

      <!--The default slot is used then-->
    </template>
  </VFlexTable>
</template>