Quasar's QTable: The ULTIMATE Component (4/6) - ALL The Slots!
Tags: quasar, vue, javascript, webdev
Published: 2021-08-19 13:19:03

What's black, blue, and PACKED full of QTable slots?

...

The video version of this blog post!

{% youtube cxNvoSkeLcM %}

The ideal progression for customizing **rows** with Quasar's `QTable` is this:
1. **No slots**, only props
2. The **generic** "cell" slot (`#body-cell`)
3. **Specific** "cell" slots (`#body-cell-[name]`)
4. **Row** slots (`#body`)

The further down the list, the more **flexibility** and **control** you wield!
The further up the list, the more **ease** and abstraction.

So keep that in mind! **If slots aren't needed, don't use them**. They're there to offer flexibility when the defaults and props aren't enough.

Make sense?

Sweet! With that in mind, we'll dive in to Quasar's slots...

Oh! And if you want to [learn all 72 of Quasar's components](https://quasarcomponents.com) through videos, checkout [QuasarComponents.Com](https://quasarcomponents.com) 😉

## Setup
First, for all you **git cloners** out there, Here's the [GitHub Repo](https://github.com/ldiebold/q-table-blog)!

...

We'll use a similar setup to past examples with a couple of additions:

First, install `lodash-es`

```shell
yarn add lodash-es
```

Why lodash-es? Because it allows us to **import individual functions** easily without bringing in the THE WHOLE OF LODASH which is a **MASSIVE** dependency!

*ahem*, anywho...

Here's the setup:

```javascript
<script>
import { copyToClipboard } from 'quasar'
import { ref } from 'vue'
import { sumBy, meanBy } from 'lodash-es'

export default {
  setup () {
    const rows = ref([
      {
        id: 1,
        name: 'Panda',
        email: 'panda@chihuahua.com',
        age: 6
      },
      {
        id: 2,
        name: 'Lily',
        email: 'lily@chihuahua.com',
        age: 5
      }
    ])

    const columns = ref([
      { label: 'name', field: 'name', name: 'name', align: 'left' },
      { label: 'email', field: 'email', name: 'email', align: 'left' },
      { label: 'age', field: 'age', name: 'age', align: 'center' }
    ])

    return {
      copyToClipboard,
      rows,
      columns,
      sumBy,
      meanBy
    }
  }
}
</script>
```
Quasar comes with a handy **copy to clipboard** utility function that we'll use in one of the examples.

We'll also use `sumBy` and `meanBy` to build a **summary row**, and an **average row**.

I've also used `ref` for the columns. Usually, you shouldn't do this since columns are almost never reactive! I've done it here, because in one of the examples we'll **make columns editable**!

Okay, put on your snorkel and we'll **dive** in 🤿

## Generic Cell Slots (#body-cell)
Want to make all cells "copyable" with the press of a button?

no problem! We can use the `#body-cell` prop for that...

```vue
<q-table
  :rows="rows"
  :columns="columns"
  row-key="id"
>
  <template #body-cell="props">
    <q-td
      :props="props"
    >
      <q-btn
        flat
        color="primary"
        :label="props.value"
        @click="copyToClipboard(props.value)"
      />
    </q-td>
  </template>
</q-table>
```
![Customizing Quasar Table Cells With Slots](https://i.imgur.com/WfIZFhg.png)

This is an easy way to **target every cell**. Notice that we're passing `props` to `q-td`? This basically allows us to proxy "Quasar Table Cell Stuff" easily 👍

Also notice we have **access to the cells value** with `props.value`!

But what if we want to target **specific** cells...

## Specific Cell Slots (#body-cell-[name])
tack on "name" and you can target any cell you like within a row.

You'll likely end up using this a lot, it's very handy! It's particularly useful for a **delete button** cell at the end of a row.

In this example, we use it to simply alternate colors:
```vue
<q-table
  :rows="rows"
  :columns="columns"
  row-key="id"
>
  <template #body-cell-name="props">
    <q-td
      class="bg-blue-1"
      :props="props"
    >
      {{ props.value }}
    </q-td>
  </template>

  <template #body-cell-email="props">
    <q-td
      class="bg-blue-2"
      :props="props"
    >
      {{ props.value }}
    </q-td>
  </template>

  <template
    #body-cell-age="props"
  >
    <q-td
      class="bg-blue-1"
      :props="props"
    >
      {{ props.value }}
    </q-td>
  </template>
</q-table>
```

![Customizing Specific Quasar Table Cells With Slots](https://i.imgur.com/f3rlNKy.png)

The API for `#body-cell-[name]` is almost identical to `#body-cell` (Classic Quasar! amazingly consistent API 🎉)

## Row Slots (#body) (editable cells)

Before looking at this example, I want you to notice two things:
1. `props` is proxied to `q-tr` AND `q-td`. Once again, this is important as it allows Quasar to take control over the cell for things like "hiding columns" and setting the `row-key`
2. We use `dense` and `borderless` on `q-input`, otherwise it looks strange in a table cell!

```vue
<q-table
  :rows="rows"
  :columns="columns"
  row-key="id"
>
  <template #body="props">
    <q-tr
      :props="props"
    >
      <q-td
        key="name"
        :props="props"
      >
        <q-input
          v-model="props.row.name"
          borderless
          dense
        />
      </q-td>
      <q-td
        key="email"
        :props="props"
      >
        <q-input
          v-model="props.row.email"
          borderless
          dense
        />
      </q-td>
      <q-td
        key="age"
        :props="props"
      >
        <q-input
          v-model="props.row.age"
          borderless
          dense
          input-class="text-center"
        />
      </q-td>
    </q-tr>
  </template>
</q-table>
```

![Quasar QTable With Editable Cells](https://i.imgur.com/8cYmbJ9.png)

Doesn't look like much does it?

But take a look at that code... we're using `QInput`'s in the cells... **These cells are EDITABLE!!!**

This is a common question in the community.

>"How do we achieve editable cells with q-table?"

well **that** my friends ☝️☝️☝️, is how 😉

-----

The rest of this blog post will be very **example driven** with less eplanation.

The aim is to make you aware of what's possible, so you can go to bed tonight **dreaming of table possibilities**! 💤💭😶‍🌫️ (I have no idea what that second emoji is. Found it on emojifinder.com when searching for "dream")

**SO!**

Ready for this?

Sweet! Let's go nuts!!!

-----

## Header Cell Slots
Pretty much the same concept as `body-cell` slots
```vue
<q-table
  :rows="rows"
  :columns="columns"
  row-key="id"
>
  <template #header-cell="props">
    <q-th
      style="font-size: 1.4em;"
      class="text-primary"
      :props="props"
    >
      {{ props.col.label }}
    </q-th>
  </template>
</q-table>
```
![Quasar QTable Header Cell Slots](https://i.imgur.com/ndADNte.png)

## Specific Header Cell Slot
```vue
<q-table
  :rows="rows"
  :columns="columns"
  row-key="id"
>
  <template #header-cell-email="props">
    <q-th :props="props">
      <q-icon
        size="sm"
        name="email"
        class="q-mr-sm"
        color="grey-7"
      />{{ props.col.label }}
    </q-th>
  </template>
</q-table>
```
![Quasar QTable Specific Header Cell Slot](https://i.imgur.com/89ISRBv.png)


## Header Row Slot
In this example, we make the header cells editable! Cool stuff 😎
```vue
<q-table
  :rows="rows"
  :columns="columns"
  row-key="id"
>
  <template #header="props">
    <q-tr>
      <q-th
        key="name"
        :props="props"
      >
        <q-input
          v-model="columns[0].label"
          dense
          borderless
          input-class="text-bold"
        />
      </q-th>

      <q-th
        key="email"
        :props="props"
      >
        <q-input
          v-model="columns[1].label"
          dense
          borderless
          input-class="text-bold"
        />
      </q-th>

      <q-th
        key="age"
        :props="props"
      >
        <q-input
          v-model="columns[2].label"
          dense
          borderless
          input-class="text-bold text-center"
        />
      </q-th>
    </q-tr>
  </template>
</q-table>
```
![Quasar QTable Header Row Slot](https://i.imgur.com/Utux5Zi.png)


## Bottom And Top Row Slot
Great for aggregations and averages! This is where we use those lodash functions...
```vue
<q-table
  :rows="rows"
  :columns="columns"
  row-key="id"
>
  <template #top-row>
    <q-tr class="bg-blue-1">
      <q-td class="text-bold">
        Average:
      </q-td>
      <q-td />
      <q-td class="text-center">
        {{ meanBy(rows, 'age') }}
      </q-td>
    </q-tr>
  </template>

  <template #bottom-row>
    <q-tr class="bg-green-1">
      <q-td class="text-bold">
        Total:
      </q-td>
      <q-td />
      <q-td class="text-center">
        {{ sumBy(rows, 'age') }}
      </q-td>
    </q-tr>
  </template>
</q-table>
```
![Quasar QTable Bottom And Top Row Slot](https://i.imgur.com/GoskK5f.png)


## Top Slot (**above** the actual table)
Perfect for things like **filters** and a **search input**
```vue
<q-table
  :rows="rows"
  :columns="columns"
  row-key="id"
>
  <template #top>
    <div
      class="text-bold"
      style="font-size: 1.3em;"
    >
      Cute Pups
    </div>
    <q-input
      class="q-ml-md"
      dense
      outlined
      placeholder="Search"
    >
      <template #prepend>
        <q-icon name="search" />
      </template>
    </q-input>
  </template>
</q-table>
```
![Quasar QTable Customizing the Top With A Search Input](https://i.imgur.com/5UcRa96.png)


## Bottom Slot (**below** the actual table)
Of course, we have total control over the bottom slot!
```vue
<q-table
  :rows="rows"
  :columns="columns"
  row-key="id"
>
  <template #bottom>
    <span>
      dogs from <a href="https://poochypoochypooch.com">poochypoochypooch.com</a>
    </span>
  </template>
</q-table>
```
![Quasar QTable Customizing The Bottom](https://i.imgur.com/NoWgCLO.png)


## Top Left and Top Right Slot
I like using `#top-left` and `#top-right` more than `#top`. I almost always want something on either side, so it feels nicer than just using `#top`...
```vue
<q-table
  :rows="rows"
  :columns="columns"
  row-key="id"
>
  <template #top-left>
    <div
      class="text-bold"
      style="font-size: 1.3em;"
    >
      Cute Pups
    </div>
  </template>
  <template #top-right>
    <q-input
      class="q-ml-md"
      dense
      outlined
      placeholder="Search"
    >
      <template #prepend>
        <q-icon name="search" />
      </template>
    </q-input>
  </template>
</q-table>
```
![Quasar QTable Top Left and Top Right Slot](https://i.imgur.com/GJIH80S.png)


## No Data Slot
Of course, we can completely overwrite the message for **no-data**...
```vue
<q-table
  :rows="[]"
  :columns="columns"
  row-key="id"
>
  <template #no-data>
    <div>Hmmm, I can't find any dang data!</div>
  </template>
</q-table>
```
![Quasar QTable No Data Slot Example](https://i.imgur.com/tmA1Ah9.png)

## And That's It!
🎉🍾🎊🤗

Now, a question...

## Can I Share My Story With You?
If you enjoyed this post **half as much** as I enjoyed making it for you, we'll be best friends!

And if you'd like to hear some of my story, head on over to [QuasarComponents.Com](https://quasarcomponents.com).

I'll [share the journey that lead to my love of Quasar](https://quasarcomponents.com), and tell you about the [**Massive** component series](https://quasarcomponents.com) I'm currently working on 🙃

So [Click Here](https://quasarcomponents.com), and I'll see you on the other side!

...

Thanks for reading and remember,

There is **nothing** you can't build...