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>
Related
I have a code have fetched from the laravel backend and passed it to vue frontend. the data is a table with records. I have already implemented it.
I have a payment tab which i want it to redirect to a specific page using the id to display data of the individual.
I have tried the router-push how do i implement it
this is my implementation code
<template>
<v-data-table hide-actions flat :headers="headers" :items="doctors" :pagination.sync="pagination"
:rows-per-page-items="pagination.rowsPerPageItems"
:total-items="pagination.totalItems">
<template v-slot:items="props">
<td>{{ props.index + 1 }}</td>
<td>{{ props.item.full_name }}</td>
<td>{{ props.item.email }}</td>
<td>{{ 'Doctor' }}</td>
<td><button class="disabled btn btn-success">amount</button></td>
<td>
<v-btn outline small color="indigo" #click="view(props.item)">
<i class="fa fa-eye"></i> make payment
</v-btn>
</td>
</template>
<template v-slot:no-results>
<h6 class="grey--text">No data available</h6>
</template>
</v-data-table>
<div class="text-center">
<v-pagination
v-model="page"
:length="4"
circle
>
</v-pagination>
</div>
</div>
</template>
<script>
import {mapActions, mapGetters} from "vuex";
export default {
data() {
return {
page: 1,
dateFormat: "DD MMM, YYYY",
selected: null,
dialog: false,
loading: false,
saveLoader: false,
pagination: {
descending: true,
page: 1,
rowsPerPage: 10,
sortBy: 'fat',
totalItems: 0,
rowsPerPageItems: [1, 2, 4, 8, 16]
},
headers: [
{text: "#", value: ""},
{text: "name", value: "name"},
{text: "email", value: "email"},
{text: "role", value: "role"},
{text: "updated_at", value: "updated_at"},
{text: "Action", value: "action"},
],
};
},
computed: {
...mapGetters({
doctors: "getListDoctors",
}),
},
methods: {
...mapActions({
fetchDoctors: 'setListDoctors'
}),
view() {
console.log(this.doctors)
// window.open(`/finance/pay-doctors/${item.id}`, "_blank");
},
},
async mounted() {
await this.fetchDoctors();
},
}
</script>
Try this.
let routeData = this.$router.resolve({name: 'routeName', query: {data: "someData"}});
window.open(routeData.href, '_blank');
How do i display data from the database. I have fetched data as an object when displaying it works well but when i convert the data to array it does not display the content of the table.
Am also trying to implement the routing such that when one clicks the button on the Actions column it redirect to another page that has a specific user details.
Am getting the data from the API and in the network fetch xhr am able to see the data.
This is the vue template where i want to display the data received by the API I guess am going wrong somewhere
<v-data-table hide-actions flat :headers="headers" :="doctors">
<template v-slot:items="props">
<td>{{ props.index + 1 }}</td>
<td>{{ props.item.full_name }}</td>
<td>{{ props.item.email }}</td>
<td>{{ props.item.username }}</td>
<td>{{ props.item.username }}</td>
<td>
<v-btn outline small color="indigo" #click="view(props.item)">
<i class="fa fa-eye"></i> make payment
</v-btn>
</td>
</template>
<template v-slot:no-results>
<h6 class="grey--text">No data available</h6>
</template>
</v-data-table>
</div>
</template>
<script>
import {mapActions, mapGetters} from "vuex";
export default {
data() {
return {
page: 1,
dateFormat: "DD MMM, YYYY",
selected: null,
dialog: false,
loading: false,
saveLoader: false,
headers: [
{text: "#", value: ""},
{text: "name", value: "name"},
{text: "email", value: "email"},
{text: "role", value: "role"},
{text: "updated_at", value: "updated_at"},
{text: "Action", value: "action"},
],
};
},
computed: {
...mapGetters({
doctors: "getListDoctors",
}),
},
methods: {
...mapActions({
fetchDoctors: 'setListDoctors'
}),
view(id) {
this.$router.push({ path: `/finance/pay-doctors/${item.id, '_blank'}` });
}
},
mounted() {
this.fetchDoctors();
},
}
</script>
Here is sample of data received from the API
{
"data": [
{
"id": 1,
"name": "TEST JOHN",
"full_name": "Mrs. JOHN",
"mobile": "0700000001",
"email": "TEST#TEST.com",
"active": 0,
"created_at": "Sep 10, 2019 07:01:43 am",
"roles": "testpharm",
"username": "USER1"
},
]
}
This should work fine regarding the doc
<template>
<v-data-table hide-actions flat :headers="headers" :items="doctors" :items-per-page="5">
<template v-slot:body="{ items }">
<tbody>
<tr v-for="item in items" :key="item.id">
<td>{{ item.name }}</td>
<td>{{ item.full_name }}</td>
<td>{{ item.mobile }}</td>
<td>{{ item.email }}</td>
<td>{{ item.username }}</td>
</tr>
</tbody>
</template>
<template v-slot:no-results>
<h6 class="grey--text">No data available</h6>
</template>
</v-data-table>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
export default {
data() {
return {
headers: [
{ text: "#", value: "" },
{ text: "name", value: "name" },
{ text: "email", value: "email" },
{ text: "role", value: "role" },
{ text: "updated_at", value: "updated_at" },
{ text: "Action", value: "action" },
],
};
},
computed: {
...mapGetters({
doctors: "getListDoctors",
}),
},
async mounted() {
await this.fetchDoctors();
},
}
</script>
Use your Vue devtools to be sure to pass data.data to the final doctors Vuex getter (regarding your JSON example).
Vue devtools will help you see what state you currently have + the usage of the network tab can also help quite a lot.
<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
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 have a table populated with json data. There is a column 'edit' in every row. When I click on edit a dialog opens up with a form. I want to edit the table data in the form. The value of input fields of the form should show the json data. But it's not showing.
I tried fill up the form using v-model="editedItem.type".
This is my table:
<v-data-table
:items="myjson">
<template v-slot:items="props">
<td>{{ props.item.ApplicationType }}</td>
<td>{{ props.item.ApplicationID }}</td>
<td>
{{props.item.APIToken}}
</td>
<td>{{ props.item.ApplicationName }}</td>
<td >
<img src="edit.svg" #click="editItem(props.item)"> Edit
</td>
</template>
</v-data-table>
This is my json data
{
"Applications": [{
"ApplicationID": "74382DOD",
"ApplicationName": "OIMInstance2",
"ApplicationType": "OIM",
"APIToken": "ZM8R4FRiZWWKbl235u06zbArCdOBPlEKhqHQO8Y9RJ2HgBPC+cZgbIli8fFuNZaey/2tJciJuILIWIn24WTjGA=="
}, {
"ApplicationID": "943ODA6G",
"ApplicationName": "LDAPInstance2",
"ApplicationType": "LDAP",
"APIToken": "R9lDEW5dnN6TZg2sefEEzS6LWMNmFh4iLHMu47LmAsusHl0bZuh2rktSlXqSZRdHHEWq7sP4Xsdy6xNtDYE8xw=="
}]
}
This is my form:
<v-text-field v-model="editedItem.type" label="Type"></v-text-
<v-text-field v-model="editedItem.id" label="ID"></v-text-field>
<v-text-field v-model="editedItem.tok" label="API Token"></v-text-field>
<v-text-field v-model="editedItem.name" label="Name"></v-text-field>
This is my script:
import json from '../../static/mockdata.json'
data: () => ({
myjson: [],
dialog: false,
editedIndex: -1,
editedItem: {
type: '',
id: '',
tok: '',
name: ''
}
},
created () {
this.myjson = json.Applications
},
methods: {
editItem (item) {
this.editedIndex = json.Applications.indexOf(item)
this.editedItem = Object.assign({}, item)
this.dialog = true
}
}
The problem is that you use non-existent keys for the form fields (type, id, tok, name). Try this:
<v-text-field v-model="editedItem.ApplicationType" label="Type"></v-text-field>
<v-text-field v-model="editedItem.ApplicationID" label="ID"></v-text-field>
<v-text-field v-model="editedItem.APIToken" label="API Token"></v-text-field>
<v-text-field v-model="editedItem.ApplicationName" label="Name"></v-text-field>
[ https://jsfiddle.net/2qawL6cg/ ]