DEV Community

Cover image for Quasar's QTable: The ULTIMATE Component (3/6) - Loading State, Pagination, and Sorting
Luke for Quasar

Posted on • Edited on

Quasar's QTable: The ULTIMATE Component (3/6) - Loading State, Pagination, and Sorting

Here's the video version...

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 if you'd like to Learn All 72 Of Quasar's Components!


Now let's begin!

Setup

Just want the code? Here's the github repo! 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

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



{
  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: "« 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
  }
}


Enter fullscreen mode Exit fullscreen mode

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:



yarn add axios


Enter fullscreen mode Exit fullscreen mode

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



<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>


Enter fullscreen mode Exit fullscreen mode

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...



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


Enter fullscreen mode Exit fullscreen mode

Quasar QTable Basic Loading State

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:



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


Enter fullscreen mode Exit fullscreen mode

Quasar QTable Loading State With Slots

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



export default defineComponent({
  setup () {
    // ...
    const pagination = ref({
      sortBy: 'name',
      descending: false,
      page: 1,
      rowsPerPage: 3
    })

    return {
      // ...
      pagination
    }
  }
}


Enter fullscreen mode Exit fullscreen mode

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:



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


Enter fullscreen mode Exit fullscreen mode

Quasar QTable Basic Pagination

Pretty cool huh?

AND, we can even change those Rows per page options with a prop:



<q-table
  v-model:pagination="pagination"
  :rows-per-page-options="[3, 5, 10, 0]"
  color="secondary"
  :loading="loading"
  :rows="dogs"
  :columns="columns"
/>


Enter fullscreen mode Exit fullscreen mode

Quasar QTable Rows Per Page Pagination

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 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⬇️



<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>


Enter fullscreen mode Exit fullscreen mode

⬆️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

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...



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 }
]


Enter fullscreen mode Exit fullscreen mode

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

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)



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)
    }
  }
]


Enter fullscreen mode Exit fullscreen mode

Bon Appétable!

Quasar QTable Custom Sort By Email Domain

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 and let me to take you on a journey you'll never forget!

I'll teach you all 72 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!


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...

Top comments (2)

Collapse
 
irina_kats profile image
Irina Kats • Edited

Very helpful article and the API! I had to solve a slightly more complex problem: have the pagination not only on the server side but also controlled by the parent of my component. With your article and the docs, I've managed it.

By the way, we don't have to empty out :rows-per-page-options="[]" for server-side pagination. As long as the API endpoint accepts pagination.value.rowsPerPage in request params and respects it in its output, it's perfectly workable. In my setup I control it not only at the bottom but also at the top, both ways it works.

And your unique style helps!

Collapse
 
youssefba78 profile image
youssefba78 • Edited

do we have Pipelining data to reduce Ajax calls in q-table quasar like DataTable

like this one : datatables.net/examples/server_sid...