<template>
<div>
<v-data-table
:items="agents"
hide-default-footer
class="agent-table"
v-bind:pagination.sync="pagination">
<template slot="item" slot-scope="props">
<tr>
<td>{{ props.item.first_name }} {{ props.item.last_name }}</td>
<td>{{ props.item.email }}</td>
<td>{{ props.item.phone }}</td>
</tr>
</template>
</v-data-table>
<div >
<v-pagination v-model="pagination.page" :length="pages" :total-visible="7"></v-pagination>
</div>
</div>
<template>
<script>
export default {
data: function() {
return {
pagination: {
rowsPerPage: 15,
page: 1
},
agents:[]
}
},
computed: {
pages () {
return this.pagination.rowsPerPage && this.agents.length !== 0 ? Math.ceil(this.agents.length / this.pagination.rowsPerPage) : 0
},
},
created() {
this.fetchAgents();
}
methods: {
fetchAgentss() {
var that = this;
this.$axios.get('agents.json')
.then(response => {
that.agents = response.data.agents;
});
}
}
}
</script>
I am upgrading from vuetify version 1.0.5 to 2.3.10 and I am using v-pagination for custom pagination but I am getting this error
[breaking] 'pagination' has been removed, use 'options' instead
Please help me find where I am going wrong
Instead of using v-bind:pagination.sync use v-bind:options.sync
{
page: number,
itemsPerPage: number,
sortBy: string[],
sortDesc: boolean[],
groupBy: string[],
groupDesc: boolean[],
multiSort: boolean,
mustSort: boolean
}
Refer Official API
For Example
Related
Company Profile
<dashboard-card
title="Company Profile"
titleColor="primary"
#click.native="componentClicked"
id="company-profile" class="vs-con-loading__container"
:isData= "isData"
>
<div class="w-full text-xl md:text-2xl font-bold">
{{ profile.companyName }}
</div>
<div class="md:text-md">
<div class="py-2">
{{ profile.description }}
</div>
<table class="table-auto border-collapse">
<tr>
<td class="py-1 pr-2 md:pr-4 font-bold">CEO:</td>
<td>{{ profile.ceo }}</td>
</tr>
<tr>
<td class="py-1 pr-2 md:pr-4 font-bold">Exchange:</td>
<td>{{ profile.exchange }}</td>
</tr>
<tr>
<td class="py-1 pr-2 md:pr-4 font-bold">Ticker:</td>
<td class="uppercase text-primary font-semibold">
{{ profile.symbol }}
</td>
</tr>
<tr>
<td class="py-1 pr-2 md:pr-4 font-bold">Industry:</td>
<td>{{ profile.industry }}</td>
</tr>
<tr>
<td class="py-1 pr-2 font-bold">Sector:</td>
<td>{{ profile.sector }}</td>
</tr>
</table>
<div class="pt-2">
<vs-icon
:icon="'icon-globe'"
icon-pack="feather"
class="text-primary pr-2"
></vs-icon>
<a class="text-primary" :href="profile.website" target="blank">
{{ profile.website }}
</a>
</div>
</div>
</dashboard-card>
</template>
<script>
import DashboardCard from "../dashboard-card";
export default {
name: "CompanyProfile",
extends: DashboardCard,
components: { DashboardCard },
props: {
ticker: {
type: String,
default: "",
},
},
data() {
return {
profile: {},
isData: "",
};
},
watch: {
ticker(value) {
this.isData = "";
this.getProfile(value);
},
},
mounted() {
this.isData = "";
this.getProfile(this.ticker);
},
methods: {
getProfile(ticker) {
this.$vs.loading({
container: "#company-profile",
type: "point",
scale: 0.8,
});
this.$api.ticker.profile(ticker).then((response) => {
if (Object.keys(response).length == 0) {
console.log("response is empty");
this.isData = "404";
this.$vs.loading.close("#company-profile > .con-vs-loading");
return;
}
this.profile = response;
this.$vs.loading.close("#company-profile > .con-vs-loading");
}).catch(error => {
console.log("error is in company Profile ", error);
if(error.response) {
this.isData = error.response.status.toString();
} else {
this.isData = "Network Error";
}
this.$vs.loading.close("#company-profile > .con-vs-loading");
});
},
},
};
</script>
Dashboard Card (where I'm applying the Blur effect)
<template>
<BaseTHCard
:title="title"
:titleColor="titleColor"
:actionable="actionable"
:fixed-height="fixedHeight"
#click.native="componentClicked"
>
<blur :isData="isData">
<!-- DEFAULT TRADEHAT CARD HEADER SLOT -->
<div slot="header">
<slot name="header"> </slot>
</div>
<!-- DEFAULT TRADEHAT CARD MEDIA SLOT -->
<div slot="media">
<slot name="media"> </slot>
</div>
<!-- DEFAULT TRADEHAT CARD BODY SLOT -->
<slot></slot>
<!-- DEFAULT TRADEHAT CARD EXTRA CONTENT SLOT -->
<div slot="extra-content">
<slot name="extra-content"> </slot>
</div>
<!-- DEFAULT TRADEHAT CARD FOOTER SLOT -->
<div slot="footer">
<slot name="footer"> </slot>
</div>
</blur>
</BaseTHCard>
</template>
<script>
import BaseTHCard from "#/components/common/base-th-card";
import blur from "../../ticker-dashboard/shared/Blur";
export default {
name: "DashboardCard",
extends: BaseTHCard,
components: {
BaseTHCard,
blur
},
props: {
isData: {
type: String,
},
title: {
type: String,
default: null,
},
titleColor: {
type: String,
default: "white",
},
fixedHeight: {
type: Boolean,
default: false,
},
actionable: {
type: Boolean,
default: false,
},
},
};
</script>
I'm getting two following warnings from vue:-
I am setting the isData data option in the CompanyProfile component and passing it as a prop to DashboardCard component and sending that isData prop value to the blurr component. The functionality works fine but I'm getting the above mentioned warnings from vue. What should be the approach to fix them.
I'm trying to process some data in v-slot template, but I get the following error:
getNameFromCategory is not defined
What is wrong?
<template v-slot:items="{ row }" >
<TableView :rows="results" >
<td>{{ getNameFromCategory(row.category) }}</td>
</TableView>
</template>
<script>
export default {
components: {
TableView
},
metdods:{
getNameFromCategory
},
props: {
'results': {
type: Array,
required: true
},
}
</script>
and then in the TableVue.vue component file:
<template>
<template v-if="numRows > 0">
<tr
v-for="(row, idx) in rows"
:key="idx"
>
<slot name="items" :row="row"></slot>
</tr>
</template>
</template>
<script>
export default {
name: 'TableView',
props:{
rows: {
type: Array,
default() {
return []
},
required: true
},
}
}
</script>
It seems that the code passed through the slot template is executed in the component, but I also tried to define the 'getNameFromCategory' function there, it didn't work.
You wrote metdods instead of methods. Also the getNameFromCategory is empty i don't know if it is for the sake of the example.
Anyway it should more look like this :
<template v-slot:items="{ row }" >
<TableView :rows="results" >
<td>{{ getNameFromCategory(row.category) }}</td>
</TableView>
</template>
<script>
export default {
components: {
TableView
},
methods:{
getNameFromCategory(category) {
return category.name;
}
},
props: {
'results': {
type: Array,
required: true
},
}
</script>
I have a typical Vue data-table with a template section that displays an alert if no records are found. Problem is, that displays right away, even before my Axios method has a chance to go out and get records.
How can I prevent the flash of red warning message before the actual data loads?
<template>
<div>
<v-card>
<v-card-title>
<h1>Locations</h1>
</v-card-title>
<v-data-table :headers="headers" :items="locations" :search="search" :fixed-header="true" :loading="true" class="elevation-1">
<template v-slot:items="location">
<td>{{ location.item.id }}</td>
<td>{{ location.item.company }}</td>
<td>{{ location.item.category }}</td>
<td>{{ location.item.name }}</td>
<td>{{ location.item.city }}, {{ location.item.state }}</td>
</template>
<template v-slot:no-data>
<v-alert :value="true" color="error" icon="warning">Sorry, no locations found.</v-alert>
</template>
</v-data-table>
</v-card>
</div>
</template>
<script>
import { HTTP } from "#/utils/http-common";
export default {
name: 'LocationsList',
data() {
return {
headers: [
{ text: "Id", value: "id" },
{ text: "Company", value: "company" },
{ text: "Category", value: "category" },
{ text: "Name", value: "name" },
{ text: "City, State", value: "city" },
],
locations: [],
errors: []
};
},
created: function() {
this.getAllLocations();
},
methods: {
getAllLocations() {
HTTP.get("locations")
.then(response => {
this.locations = response.data;
})
.catch(err => {
this.errors.push(err);
});
},
}
};
</script>
Add a loading state to data, and set it to true
Set the loading state when the call is finished (.finally promise)
Set the v-if on in your template to show when it's not anymore loading
See code below.
<template>
<div>
<v-card>
<v-card-title>
<h1>Locations</h1>
</v-card-title>
<v-data-table :headers="headers" :items="locations" :search="search" :fixed-header="true" :loading="true" class="elevation-1">
<template v-slot:items="location">
<td>{{ location.item.id }}</td>
<td>{{ location.item.company }}</td>
<td>{{ location.item.category }}</td>
<td>{{ location.item.name }}</td>
<td>{{ location.item.city }}, {{ location.item.state }}</td>
</template>
<template v-slot:no-data>
<v-alert v-if="!loading" :value="true" color="error" icon="warning">Sorry, no locations found.</v-alert>
</template>
</v-data-table>
</v-card>
</div>
</template>
<script>
import { HTTP } from "#/utils/http-common";
export default {
name: 'LocationsList',
data() {
return {
headers: [
{ text: "Id", value: "id" },
{ text: "Company", value: "company" },
{ text: "Category", value: "category" },
{ text: "Name", value: "name" },
{ text: "City, State", value: "city" },
],
locations: [],
errors: [],
loading: true
};
},
created: function() {
this.getAllLocations();
},
methods: {
getAllLocations() {
HTTP.get("locations")
.then(response => {
this.locations = response.data;
})
.catch(err => {
this.errors.push(err);
})
.finally(() => {
this.loading = false;
})
},
}
};
</script>
The function "change sort" executed on header item click does not trigger watch, which fetches updated data from server. On the other hand, if I try to execute fetchRecords method at the end of changeSort method, watch gets triggered multiple times
I need to use Vuetify datatables with server side pagination and sorting, and templates for header and items. I implemented code similarly to Vuetify examples: "Paginate and sort server-side" and "Slot: items and headers" from documentation https://vuetifyjs.com/en/components/data-tables#api.
<template>
<v-card class="table-container">
<v-card-title>
<v-text-field
v-model="searchField"
#blur="fetchRecords()"
#keyup.enter="fetchRecords()"
/>
</v-card-title>
<v-data-table
:headers="headers"
:items="applications.applications"
:loading="paginationLoading"
:pagination.sync="pagination"
:total-items="pagination.totalItems"
no-data-text="No results"
>
<template v-slot:headers="props">
<tr>
<th colspan="4">Dane kandydata</th>
<th colspan="4">Dane polecającego</th>
<th colspan="2">Inne</th>
</tr>
<tr>
<th
v-for="header in props.headers"
:key="header.value"
:class="['column',
header.sortable !== false ? 'sortable' : '' ,
pagination.descending ? 'desc' : 'asc',
header.value === pagination.sortBy ? 'active' : '']"
#click="changeSort(header.value, header.sortable)"
>
{{ header.text }}
<v-icon v-if="header.sortable !== false" small>fas fa-sort-up</v-icon>
</th>
</tr>
</template>
<template v-slot:items="props">
<td>{{ props.item.candidateName }}</td>
<td>{{ props.item.candidateSurname }}</td>
<td>{{ props.item.candidateEmail }}</td>
<td>{{ props.item.candidatePhone }}</td>
<td>{{ props.item.referrerName }}</td>
<td>{{ props.item.referrerSurname }}</td>
<td>{{ props.item.referrerEmail }}</td>
<td>{{ props.item.referrerPhone }}</td>
<td class="text-md-center">
<div>
<v-icon>check_circle_outline</v-icon>
</div>
</td>
<td class="text-md-center">
<div>
<v-icon>check_circle_outline</v-icon>
</div>
</td>
</template>
<v-alert v-slot:no-results :value="true" color="error" icon="warning">
Your search for "{{ searchField }}" found no results.
</v-alert>
</v-data-table>
</v-card>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
data () {
return {
announcementId: '',
announcementTitle: '',
searchField: '',
headers: [
{ text: 'Imię', value: 'candidateName' },
{ text: 'Nazwisko', value: 'candidateSurname' },
{ text: 'Email', value: 'candidateEmail', sortable: false },
{ text: 'Telefon', value: 'candidatePhone' },
{ text: 'Imię', value: 'referrerName' },
{ text: 'Nazwisko', value: 'referrerSurname' },
{ text: 'Email', value: 'referrerEmail', sortable: false },
{ text: 'Telefon', value: 'referrerPhone' },
{ text: 'Status', value: 'processed' },
{ text: 'Akcje', value: 'actions', sortable: false },
],
pagination: {
page: 1,
rowsPerPage: 10,
totalItems: 10,
sortBy: '',
descending: false,
},
paginationLoading: false
}
},
computed: {
...mapState([
'applications',
])
},
watch: {
pagination: {
handler(newVal, oldVal){
if(newVal != oldVal){
this.fetchRecords()
}
},
deep: true
}
},
methods: {
...mapActions([
'getApplications',
]),
fetchRecords () {
this.paginationLoading = true
this.getApplications({
announcementId: this.announcementId,
pagination: this.pagination,
search: this.searchField
})
.then(
response => {
this.paginationLoading = false
if(this.pagination.totalItems != response.totalItems) this.pagination.totalItems = response.totalItems
}
)
.catch(
err => {
console.log(err);
}
)
},
changeSort (columnValue, sortable) {
if(sortable === false){
return
}
if (this.pagination.sortBy === columnValue) {
this.pagination.descending = !this.pagination.descending
console.log(this.pagination.descending);
} else {
this.pagination.sortBy = columnValue
this.pagination.descending = false
}
},
editTableItem(item){
console.log(item);
},
onClearSearch() {
this.searchField = ''
this.fetchRecords()
},
}
}
</script>
You should create new object when changing pagination object. Here I use ES6 syntax:
changeSort (columnValue, sortable) {
if(sortable === false){
return
}
if (this.pagination.sortBy === columnValue) {
this.pagination = {
...this.pagination,
descending: !this.pagination.descending
}
console.log(this.pagination.descending);
} else {
this.pagination = {
...this.pagination,
sortBy: columnValue,
descending: false
}
}
}
I want to use the vuetify framework with Vuex , but there is limited documentation about using it with Vuex.
I want to:
Get data from an external API ( but only the data needed )
Then Save the data in state and edit or whatever
Then push any changes back to the api
I have tried some of the external pagination and sorting examples with vuetify , but I can't get it to show all record count unless I hard code it.
I am quite new to Vue and Vuetify , so maybe I am misunderstanding something.
<template>
<div>
<v-data-table
:headers='headers'
:items='items'
:length='pages'
:search='search'
:pagination.sync='pagination'
:total-items='totalItemCount'
class='elevation-1'
>
<template slot='items' slot-scope='props'>
<td class='text-xs-right'>{{ props.item.id }}</td>
<td class='text-xs-right'>{{ props.item.first_name }}</td>
<td class='text-xs-right'>{{ props.item.last_name }}</td>
<td class='text-xs-right'>{{ props.item.avatar }}</td>
</template>
</v-data-table>
</div>
</template>
<script>
import moment from 'moment'
import axios from 'axios'
export default {
name: 'test-table',
watch: {
pagination: {
async handler () {
const rowsPerPage = this.pagination.rowsPerPage
// const skip = (this.pagination.page - 1) * rowsPerPage
const pageNumber = this.pagination.page
const res = await axios.get(`https://reqres.in/api/users?page=${pageNumber}&per_page=${rowsPerPage}`)
this.items = res.data.data
this.$store.commit('saveTableData', this.items)
},
deep: true
}
},
computed: {
pages () {
return 171
},
totalItemCount () {
return 400
}
},
async mounted () {
const rowsPerPage = this.pagination.rowsPerPage
const skip = (this.pagination.page - 1) * rowsPerPage
const res = await axios.get(`https://reqres.in/api/users?page=${skip}&per_page=${rowsPerPage}`)
this.items = res.data.data
this.$store.commit('saveTableData', this.items)
},
methods: {
nzDate: function (dt) {
return moment(dt).format('DD/MM/YYYY')
}
},
data: () => ({
search: '',
// totalItems: 0,
items: [],
pagination: {
sortBy: 'Date'
},
headers: [
{ text: 'ID', value: 'id' },
{ text: 'First Name', value: 'first_name' },
{ text: 'Last Name', value: 'last_name' },
{ text: 'Avatar', value: 'avatar' }
]
})
}
This is my working setup:
<template>
<v-data-table
:total-items="pagination.totalItems"
:pagination.sync="pagination"
:items="rows"
:headers="columns">
<template slot="headers" slot-scope="props">
<tr :active="props.selected">
<th v-for="column in props.headers">
{{ column.value }}
</th>
</tr>
</template>
<template slot="items" slot-scope="props">
<tr>
<td v-for="cell in props.item.row">
<v-edit-dialog lazy>
{{ cell.value }}
<v-text-field
:value="cell.value"
single-line
counter>
</v-text-field>
</v-edit-dialog>
</td>
</tr>
</template>
</v-data-table>
</template>
<script>
export default {
data: () => ({
pagination: {
page: 1,
rowsPerPage: 10,
totalItems: 0
},
selected: []
}),
computed: {
columns: {
get () {
return this.$store.state.columns
}
},
rows: {
get () {
return this.$store.state.rows
}
}
},
methods: {
async getRowsHandler () {
try {
const {total} = await this.$store.dispatch('getRows', {
tableIdentifier: this.$route.params.tableIdentifier,
page: this.pagination.page,
size: this.pagination.rowsPerPage
})
this.pagination.totalItems = total
} catch (error) {
// Error
}
}
}
}
</script>
I didn't implement everything. If you miss a specific part ask again and I will update my example. One more tip: You should avoid watch deep wherever possible. It can result in heavy calculations.
Assuming this is Vuetify v1.5, the documentation on the total-items prop on data-tables states:
Caution: Binding this to a blank string or using in conjunction with
search will yield unexpected behaviours
If you remove the 'search' prop from your table the record count will show again. If you're doing external stuff anyway, you'll won't want the default search functionality.