Quasar's QTable: The ULTIMATE Component (3/6) - Loading State, Pagination, and Sorting
Tags: quasar, vue, javascript, webdev
Published: 2021-08-18 12:26:08

Here's the video version...

{% youtube jnwdEtrdRuI %}

You already know what loading state, pagination and sorting is right?

Sweet! No preamble required, let's just dive right in...

---

Oh, and [**WACK this link**](https://quasarcomponents.com) if you'd like to [**Learn All 72 Of Quasar's Components**](https://quasarcomponents.com)!

---

Now let's begin!

## Setup
Just want the code? Here's the github repo! [ldiebold/q-table-blog](https://github.com/ldiebold/q-table-blog)

We'll do some fancy pants stuff in this blog, so we'll need a backend... Luckily, I built a **free api just for you**! checkout this endpoint...

[https://table.quasarcomponents.com/dogs](https://table.quasarcomponents.com/dogs)

Take a squiz at the data! if you scroll down to the `meta` property, you'll notice that we have pagination...

```javascript
{
  data: [
    {
      id: 1,
      created_at: "2021-08-17T01:29:29.000000Z",
      updated_at: "2021-08-17T01:29:29.000000Z",
      name: "Hollie",
      email: "nshields@yahoo.com",
      age: 9
    },
    {
      id: 2,
      created_at: "2021-08-17T01:29:29.000000Z",
      updated_at: "2021-08-17T01:29:29.000000Z",
      name: "Sonya",
      email: "shields.gonzalo@douglas.info",
      age: 19
    }
  ],
  links: {
    first: "http://table.quasarcomponents.com/dogs?page=1",
    last: "http://table.quasarcomponents.com/dogs?page=34",
    prev: null,
    next: "http://table.quasarcomponents.com/dogs?page=2"
  },
  meta: {
    current_page: 1,
    from: 1,
    last_page: 34,
    links: [
      {
        url: null,
        label: "&laquo; Previous",
        active: false
      },
      {
        url: "http://table.quasarcomponents.com/dogs?page=1",
        label: "1",
        active: true
      }
    ],
    path: "http://table.quasarcomponents.com/dogs",
    per_page: 15,
    to: 15,
    total: 500
  }
}
```

>Note that much of the `data` and `links` have been removed for brevity

We'll need axios so it's easy to hit that endpoint, so let's go ahead and install it:

```shell
yarn add axios
```

Now we'll use it in our `<script>`:

```javascript
<script>
import { defineComponent, ref } from 'vue'
import axios from 'axios'

export default defineComponent({
  setup () {
    const loading = ref(true)
    const dogs = ref([])

    const columns = [
      { name: 'name', label: 'Name', field: 'name', align: 'left' },
      { name: 'age', label: 'Age', field: 'age', align: 'center' },
      { name: 'email', label: 'Email', field: 'email' }
    ]

    // Fetch dogs
    axios.get('https://table.quasarcomponents.com/dogs')
      .then(response => {
        dogs.value = response.data.data
      })
      .finally(() => {
        loading.value = false
      })

    return {
      columns,
      loading,
      dogs
    }
  }
})
</script>
```

If you've read the prior two posts, this might be starting to make sense...

We setup some **data**, do some **column** config, **fetch the dogs**, update our `dogs` array, toggle the `loading` state, and expose it to the template!

## Loading State
Quasar gives us a simple, beautiful loading bar when we set the `loading` prop to `true`. It also respects the tables `color` prop!

Here, I'll show you...

```vue
<q-table
  color="secondary"
  :loading="loading"
  :rows="dogs"
  :columns="columns"
/>
```

![Quasar QTable Basic Loading State](https://i.imgur.com/6b3ocYi.png)

That's it! You might need to refresh the page to see it loading (especially if you're in Paris, cause that's where the server is!)

You could also just set `:loading="true"`. I usually do this when playing with the styling!

So that's basic loading but of course...

Quasar gives us **TOTAL control** with slots 🙃

## The `#loading` Slot
Take a look at the `#loading` slot in this example:

```vue
<q-table
  :loading="loading"
  :rows="dogs"
  color="primary"
>
  <template #loading>
    <q-inner-loading
      showing
      color="primary"
    />
  </template>
</q-table>
```

![Quasar QTable Loading State With Slots](https://i.imgur.com/qxN8ZjT.png)

Using Quasar's `QInnerSpinner` component, we can create a beautiful alternative way of displaying "loading".

I personally think **this looks sweet!**

Alright, that's enough loading you crazy dev you 😁. Let's take a look at pagination.

## Pagination
Quasar's `QTable` gives you **everything you need for pagination** by allowing you to model `pagination`.

let's add it to our script
```js
export default defineComponent({
  setup () {
    // ...
    const pagination = ref({
      sortBy: 'name',
      descending: false,
      page: 1,
      rowsPerPage: 3
    })
  
    return {
      // ...
      pagination
    }
  }
}
```

Most of those pagination options likely make sense to you. Note that Quasar also gives us `sortBy` and `descending`.

`sortBy` and `descending` allow us to set a **default sort** to our table. Where I work, **we use this a lot** as clients often want to see their data in **alphabetical order** by default.

I'll show you later how it's possible to **change the sort algorithm** (I always feel smart using the word "algorithm")

Now let's **model this pagination data** in the table:

```vue
<q-table
  v-model:pagination="pagination"
  color="secondary"
  :loading="loading"
  :rows="dogs"
  :columns="columns"
/>
```

![Quasar QTable Basic Pagination](https://i.imgur.com/HlJNFTf.png)

Pretty cool huh?

AND, we can even change those **Rows per page options** with a prop:
```vue
<q-table
  v-model:pagination="pagination"
  :rows-per-page-options="[3, 5, 10, 0]"
  color="secondary"
  :loading="loading"
  :rows="dogs"
  :columns="columns"
/>
```

![Quasar QTable Rows Per Page Pagination](https://i.imgur.com/BPZHtMd.png)

Gosh I love Quasar ❤️

If you're a **POWER user**, you might be crossing your arms thinking "yea, but I need **server side** pagination. Server side pagination is always a pain to implement."

Well **uncross those arms** because it's a piece of pecan pie with Quasar!

## Server Side Pagination (A Piece Of Pecan Pie)
This is why I build the [https://table.quasarcomponents.com/dogs](https://table.quasarcomponents.com/dogs) api! So we can easily play with server side pagination...

I'm going to **move my explanation into the code**, since this example is a little more involved! See you there...

⬇️*Jumps into code block below*⬇️

```vue
<template>
  <!--
    Why hello there!
    Meet me at the "script" section. That's where the magic happens 🪄
  -->
  <q-page
    padding
    class="flex justify-center"
  >
    <div
      class="full-width q-gutter-xl"
    >
      <!--
        Two things to notice here
        1. "rows-per-page-options" has been emptied.
            We're going to let the server decide how many "rows per page"
        2. @request is fired whenever a pagination is clicked! Handy 🙂
       -->
      <q-table
        v-model:pagination="pagination"
        :rows-per-page-options="[]"
        color="secondary"
        :loading="loading"
        :rows="dogs"
        :columns="columns"
        @request="onRequest"
      />
    </div>
  </q-page>
</template>

<script>
import { defineComponent, ref } from 'vue'
import axios from 'axios'

export default defineComponent({
  setup () {
    // And here we are!
    // I'll only comment on the parts that are different 😉
    const loading = ref(true)
    const dogs = ref([])

    const pagination = ref({
      // No longer using sort. if needed, this can now be done using the backend!
      // sortBy: 'name',
      // descending: false,
      page: 1,
      rowsPerPage: 15,
      // When using server side pagination, QTable needs
      // to know the "rows number" (total number of rows).
      // Why?
      // Because Quasar has no way of knowing what the last page
      // will be without this information!
      // Therefore, we now need to supply it with a "rowsNumber" ourself.
      rowsNumber: 0
    })

    const columns = [
      { name: 'name', label: 'Name', field: 'name', align: 'left', sortable: true },
      { name: 'age', label: 'Age', field: 'age', align: 'center' },
      { name: 'email', label: 'Email', field: 'email' }
    ]

    // Fetch dogs
    const fetchDogs = (page = 0) => { // we can specify the "page" to jump to
      loading.value = true
      return axios.get('https://table.quasarcomponents.com/dogs', {
        params: { page: page } // here, we tell the api what "page" to jump to
      })
        .then(response => {
          dogs.value = response.data.data
          // The api gives us "meta data".
          // this meta data gives us everything we
          // need to get pagination working!
          const meta = response.data.meta

          // We now update "pagination" with our meta data
          // from the server. This is where the magic happens 🪄
          pagination.value.page = meta.current_page
          pagination.value.rowsPerPage = meta.per_page
          pagination.value.rowsNumber = meta.total
        })
        .finally(() => {
          loading.value = false
        })
    }

    // QTable exposes a @request method (see the <template>)
    // This will be called when one of the pagination buttons are clicked.
    // it gives us everything we need, including the new page number!
    const onRequest = (props) => {
      fetchDogs(props.pagination.page)
    }

    // The initial fetch
    fetchDogs()

    return {
      onRequest,
      columns,
      loading,
      dogs,
      pagination
    }
  }
})
</script>
```

⬆️*Jumps out of code block*⬆️

**HOW COOL WAS THAT!!??**

Being **INSIDE** a code block is strange... It was kinda cold in there, will have to take a coat next time 🧥

Anywho,

Let's take a look at the result:

![Quasar QTable Server Side Pagination](https://i.imgur.com/OiUTatl.png)

So there you go. Server side pagination is a blast with Quasar!

And if you **really** want total control, you could use Quasar's `QPagination` component and completely replace `QTable`'s pagination.

Right, let's move on to the **last topic** for today/night/evening/morning (us devs are worldy people)...

## Sorting
Want basic sorting? Quasar's got ya sorted! HA! **I made a joke!!!**

*ahem*

Sorting is only **one prop away...**

```javascript
const columns = [
  { name: 'name', label: 'Name', field: 'name', align: 'left', sortable: true },
  { name: 'age', label: 'Age', field: 'age', align: 'center', sortable: true },
  { name: 'email', label: 'Email', field: 'email', sortable: true }
]
```

Notice we set `sortable: true` on all the columns?

Also, notice that when we hover over one of the "heading" cells, we get a **sort arrow...**
![Quasar QTable Basic Sorting](https://i.imgur.com/z965MkA.png)

`sortable: true` will do the job most of the time, otherwise we can use...

## Custom Sorting
Need to use your own sort function? No problem!

In this example, we'll sort using **email** by **domain** (e.g. gmail.com, hotmail.com, quasarcast.com etc)

```javascript
const columns = [
  { name: 'name', label: 'Name', field: 'name', align: 'left', sortable: true },
  { name: 'age', label: 'Age', field: 'age', align: 'center', sortable: true },
  {
    name: 'email',
    label: 'Email',
    field: 'email',
    sortable: true,
    sort: (a, b) => {
      const domainA = a.split('@')[1]
      const domainB = b.split('@')[1]
      return domainA.localeCompare(domainB)
    }
  }
]
```

**Bon Appétable!**

![Quasar QTable Custom Sort By Email Domain](https://i.imgur.com/zkG3RSw.png)

We're now sorting with our own sorter! Sorta cool right?

## "What's Next?""
In the next post, I'm going to gift you with QTable's ultimate power!

We're going to cover **All of Quasar's Slots!!!**

You're not gonna wanna miss it! Slots give `QTable` **UNLIMITED** flexibility 💪

## For Those That Need A Little More...
Quasar has a **huge**, impressive component library.

The APIs will **bring you to your knees** with joy! The flexibility will have you **nodding your head with approval**, and the beautiful community will lead you to **fall in love** with this framework.

Sound like something worth exploring?

**Of course it is!**

Now head on over to [QuasarComponents.Com](https://quasarcomponents.com) and let me to **take you on a journey you'll never forget!**

I'll teach you [**all 72**]((https://quasarcomponents.com)) of Quasar's components in **action packed** videos that will leave you **excited to code!!!**

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

---

That's all my dear dev friends. Now can you please do me a **very important favour**?

Go to bed tonight remembering, and dreaming about **this one thing**,

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