V-data-table showing total number of pages - datatable

Good morning,
I am creating the table with pagination in my project using v-data-table.
All is working correctly, I am just trying to add total number of pages to the pagination.
What I have now:
<v-data-table
:headers="headers"
:items="filteredList"
:items-per-page="7"
no-data-text="No results"
:footer-props="{
itemsPerPageText: 'Items per page:',
itemsPerPageOptions: itemsPerPages,
showCurrentPage: true
}"
>
</v-data-table>
The thing is, showCurrentPage displays only the number of current page (between prev/next page buttons). Is it possible to change it to something like:
Page 1 of 3?
pagination screenshot

I believe there is a slot for v-data-table that will replace the page text. Personally have not used a slot for this scenario and this example is off the top of my head but it should be along the lines of:
<v-data-table>
<template v-slot:footer.page-text="{ pageStart, pageStop, itemsLength }">
{{ pageStart }} of {{ itemsLength }}
</template>
</v-data-table>
If the slot does not work as intended, then you have the option to create a custom slot for the whole footer to add the page count. Unfortunately this will replace the default footer so you will have to recreate the other elements in the footer like items per page dropdown and page navigation.
<v-data-table>
<template v-slot:footer="{ props }">
// Every other footer element
{{ props.pagination.page }} of {{ props.pagination.pageCount }}
</template>
</v-data-table>

Related

Vuetify Treeview with Pagination

I'm using the vuetify tree view component to render a large list of items:
https://vuetifyjs.com/en/components/treeview/
Is there a way to paginate the loading of the children? I've seen the pagination component but I could not find a way to add pagination to the tree view component, so currently I'm just able to load the first page of the items.
Current tree view implementation:
<v-treeview v-model="selection"
#input="on_update_selection"
selectionType="leaf"
selectable
selected-color="blue"
:load-children="fetch_children"
return-object
:items="items">
<template v-slot:prepend="{ item, open }">
<v-icon v-if="item.name.endsWith('/')" :data-cy="`import-select-node-${item.name}`">
mdi-folder
</v-icon>
<v-icon v-else>
mdi-file
</v-icon>
</template>
</v-treeview>
Any guidance on how to achieve this would be super helpful!

Multiple Vuetify Data Tables causing terrible performance?

I'm building out a Nuxt app with Vuetify, and am running into a performance issue using the Vuetify Data Tables.
On page load, I am querying for all of a user's trips. The user can then select one of those trips from a sidebar. The example user I'm testing with has a lot of categories and items contained within the first Trip, and nothing in the second Trip. When I click from the second trip back to the first trip, it takes several seconds to load the items.
From what I can tell, this bottleneck is occurring because I'm rendering a new data table for each Category (which then contains multiple Items). When I looked at the Performance tab of the Vue Devtools, I noticed that even though I am disabling pagination, sorting and filtering for the data tables, all of those events are still being fired. Here's the screenshot:
As you can see, there are upwards of 64 events being fired, most of them are duplicated twice, and events that I thought I'd disabled are still being fired. Here is a simplified version of the code that I am using:
<template>
<v-data-table
v-if="category.items"
:ref="`sortableTable${index}`"
calculate-widths
class="items-table-container"
dense
disable-filtering
disable-pagination
disable-sort
:footer-props="{ disablePagination: true, disableItemsPerPage: true }"
:headers="headers"
hide-default-footer
:items="category.items"
:mobile-breakpoint="0">
<template #body="{ items }">
<draggable
v-bind="dragOptions"
class="dragArea"
group="items"
handle=".drag"
:list="items"
tag="tbody"
#change="log"
#end="drag = false"
#start="drag = true">
<tr
v-for="(item, i) in items"
:key="item.id">
<!-- Drag Handle -->
<td
:key="`${item.id}-drag-${i}-${index}`"
class="px-0 py-1">
<custom-icon
color="#4a4a4a"
custom-class="drag"
:height="20"
name="grip-horizontal-line"
:width="20" />
</td>
<!-- Type Click To Edit -->
<td
:key="`${item.id}-type-${i}-${index}`"
class="px-0 py-1">
<click-to-edit
:style="{ fontSize: '0.875rem' }"
:unique-identifier="`type${item.id}`"
:value="item.generic_type"
#handle-update-item="updateItem($event, item, 'generic_type')" />
</td>
<!-- Other Columns, shortened to simplify -->
...
</tr>
</draggable>
</template>
</v-data-table>
</template>
Currently using Vuetify v.2.4.0.
Why are all of these events still firing? And is there a more efficient way of rendering a dozen or so Data Tables without taking such a huge performance hit?
Well, I sort of fixed it.
I ended up using Vuetify's Lazy Component, so that it's not trying to render all DOM elements at once. This has sped it up I would estimate by 75%, so much better. Not great, but better. Here's how I implanted it:
<template>
<v-row
v-for="(category, index) in trip.categories"
:key="category.id">
<v-lazy
min-height="100"
:options="{ threshold: .25}"
:style="{ width: '100%' }"
transition="fade-transition"
:value="false">
<v-col
cols="12">
<v-data-table
v-if="category.items"
:ref="`sortableTable${index}`"
calculate-widths
class="items-table-container"
dense
disable-filtering
disable-pagination
disable-sort
:footer-props="{ disablePagination: true, disableItemsPerPage: true }"
:headers="headers"
hide-default-footer
:items="category.items"
:mobile-breakpoint="0">
... custom rows
</v-data-table>
</v-vol>
</v-lazy>
</v-row>
</template>
I'm still unsure of why pagination, sorting, and filtering events are being fired even when I'm disabling those via props. I have a feeling it'd speed it up even more, so if anyone knows the answer to that, I would love to hear it!

Vue-InstantSearch with Algolia & Laravel: Hide result on empty query

I'd like to figure out how to hide the index/result on an empty search query.
In my blade I have the code (slightly modified from the official documentation):
<ais-instant-search index-name="myIndex" :search-client="searchClient">
<ais-search-box placeholder="Search here"></ais-search-box>
<ais-state-results>
<template slot-scope="{ state: { query } }">
<ais-hits v-if="query.length > 0">
<div slot="item" slot-scope="{ item }">
<h2>#{{ item.Title}}</h2>
<p>#{{ item.Text}}</p>
</div>
</ais-hits>
</template>
</ais-state-results>
</ais-instant-search>
If I enter a search query this works fine, but on empty query this displays the following unwanted notification on my page (instead of the before unwanted index):
Use this component to have a different layout based on a certain state.
Fill in the slot, and get access to the following things on the slot-scope:
results: [
"_rawResults",
"hits",
"nbHits",
[..]
How can I hide this notification?
Ah, I just found a solution I think.
This notification text is displayed if there's no DOM element inside <ais-hits>. And in case of no query there isn't, since "v-if" removes that. So If instead of "v-if" I use "v-show" it works as I need it, since the DOM element still exists, but isn't displayed (display:hidden).
<ais-instant-search index-name="myIndex" :search-client="searchClient">
<ais-search-box placeholder="Search here"></ais-search-box>
<ais-state-results>
<template slot-scope="{ state: { query } }">
<ais-hits v-show="query.length > 0">
<div slot="item" slot-scope="{ item }">
<h2>#{{ item.Title}}</h2>
<p>#{{ item.Text}}</p>
</div>
</ais-hits>
</template>
</ais-state-results>

How can I get the cell selected in a Vuetify Datatable?

I know that I can get the row selected using the event "click:row" in my Datatable component, but I need to get the specific cell that I had clicked
You can use slots for that. Add it inside of your table component like given below:
<template v-slot:item.name="{ item }">
<div #click="rowClicked(item)">
<v-icon
class="mr-2"
color="#54a1e0"
large
>{{ "mdi-folder" }}
</v-icon>
{{ item.name }}
</div>
</template>
Here, you call a "rowClicked" method and you pass the clicked item when there is a click on "name" field that you also customise within the template.

Vuetify v-data-table showing error in props.item with nested JSON

Here's the error
TypeError: Cannot read property 'name' of undefined
at Object.fn [as items] (app.js:74266)...
Hi guys I'm working on a UsersVue component and recently updated to Vuetify and I'm getting the Users API from a Laravel backend from this controller. Any help or suggestions are appreciated, thanks.
UsersController.php
public function index()
{
//With data from ROLES table
$users = User::with('role:role_id,name')->orderBy('id','asc')->get();
return response()->json($users);
}
The props.item.role.name is showing properly and the add/update functionality are also working except the errors showing after I updated a user
Users.vue
<template>
<v-data-table
:headers="headers"
:items="myUsers"
:search="search"
:loading="isLoading"
class="elevation-1"
>
<v-progress-linear slot="progress" color="blue" indeterminate></v-progress-linear>
<template slot="items" slot-scope="props">
<td class="text-md-left pt-3">{{ props.item.name }}</td>
<td class="text-md-left pt-3">{{ props.item.email }}</td>
-----------------------------------------------------------------------
**<td class="text-md-left pt-3">{{ props.item.role.name }}</td>**
-----------------------------------------------------------------------
<td class="justify-content-left layout">
<v-btn icon #click.prevent="editUser(props.item)">
<v-icon color="blue">edit</v-icon>
</v-btn>
<v-btn icon #click.prevent="deleteUser(props.item)" :disabled="props.item.name === 'admin'">
<v-icon color="pink">delete</v-icon>
</v-btn>
</td>
</template>
<v-alert slot="no-results" :value="true" color="error" icon="warning">
Your search for "{{ search }}" found no results.
</v-alert>
<template slot="no-data">
<v-btn color="primary" href="/dashboard/users" >Reset</v-btn>
</template>
</v-data-table>
</template>
[Edited] VueDevTools view
myUsers.role.name has value showing ''student'' string in the v-data-table. The props.item.role.name is really the source of the errors which doesn't occur when I omitted it or changed it to a non-nested JSON like props.item.role_id.
[VueDevTools View - JSON]1
[VueDevTools View - Error]2
It's telling that in your :items="myUsers" there is no role.name.
So when when you try to do {{ props.item.role.name }} it's poping you an error.
Look in myUsers, when you're having the error, with VueDevTool for example, it should miss role.name.
Find a way to add it, or remove that line, and datatable will be ok.
I finally fixed my problem here. There are 2 reasons why I got the error. One in the backend (Laravel) and one in the Frontend (Vue.js).
Backend
My User and Role has One to many relationship so by using this fixed my update/edit of roles (this alone solved my problem)
$user->roles()->sync(values);
Frontend
Additionally for the minor problem, the Errors exist in updating/editing the v-data-table because I'm using
Object.assign({},obj);
which I discovered is only suited for shallow copying of objects and fail when data are updated for the deep properties inside the object. Which obviously didn't reach props.item.role.name. By using this I coped with errors
JSON.parse(JSON.stringify(obj));

Resources