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
}
}
Note that much of the
data
andlinks
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
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>
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"
/>
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>
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
}
}
}
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"
/>
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"
/>
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>
⬆️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:
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 }
]
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...
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)
}
}
]
Bon Appétable!
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)
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 acceptspagination.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!
do we have Pipelining data to reduce Ajax calls in q-table quasar like DataTable
like this one : datatables.net/examples/server_sid...