Show data from api to a table in vue js - vue.js

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.

Related

How to open a new page with the props id of a specific user on blank page and set route

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');

Hide no-data template until after data loads via Axios

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>

Vuetify datatable watch does not trigger

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

how to populate v-text-field with json data

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

How to pull data from a Vuetify Datatable selected row

I have a Vuetify Datatable
<v-data-table
:headers="headers"
:items="members"
item-key="id"
v-model="selected"
:search="search"
>
<template slot="items" slot-scope="props">
<tr :active="props.selected" #click="select(props.item)">
<td>{{ props.item.name }}</td>
<td class="text-xs-right">{{ props.item.FirstName}}</td>
<td class="text-xs-right">{{ props.item.LastName }}</td>
<td class="text-xs-right">{{ props.item.email }}</td>
<td class="text-xs-right">{{ props.item.department}}</td>
<td class="text-xs-right">{{ props.item.division}}</td>
</tr>
</template>
And when I select a row I want to be able to populate an Item on the same page with some of the data such as the name and email in a v-card. I currently have
{{msg}}
and in my script I have
return {
msg: "",
then
select(selectedItem) {
this.selected = [];
this.members.forEach(item => {
if (item.id == selectedItem.id) {
this.selected.push(item);
this.msg = selectedItem.FirstName;
}
});
},
I need to put name into the msg. I feel that I'm going the long way around to get my data and was wondering if someone has a better solution. Thanks for the support.
<v-data-table #click:row="rowClick" item-key="name" single-select ...
methods: {
rowClick: function (item, row) {
row.select(true);
//item - selected item
}
}
<style>
tr.v-data-table__selected {
background: #7d92f5 !important;
}
</style>
or
<style scoped>
/deep/ tr.v-data-table__selected {
background: #7d92f5 !important;
}
</style>
Example
https://codepen.io/nicolai-nikolai/pen/GRgLpNY
Since there is a binding between the data table and this.selected, you only need to populate msg as a computed property of the component. You don't need to manually add to this.selected by listening to the click event.
computed: {
msg() {
const selectedRow = this.selected[0];
return selectedRow ? `${selectedRow.firstName} ${selectedRow.lastName}` : "no data selected";
}
}
EDIT
I've added a minimal example. Note for the item-key prop of v-data-table, you should use unique values.
<template>
<v-card>
<v-card-text>
<v-data-table :headers="headers" :items="members" v-model="selected" item-key="id">
<template slot="items" slot-scope="props">
<td>
<v-checkbox
v-model="props.selected"
:disabled="!props.selected && selected.length != 0"
:indeterminate="!props.selected && selected.length != 0"
></v-checkbox>
</td>
<td>{{ props.item.firstName}}</td>
<td>{{ props.item.lastName }}</td>
</template>
</v-data-table>
{{ msg }}
</v-card-text>
</v-card>
</template>
<script>
export default {
data() {
return {
headers: [
{ text: "Select", value: "id", sortable: false },
{ text: "First Name", value: "firstName", sortable: true },
{ text: "Last Name", value: "lastName", sortable: true }
],
selected: [],
members: [
{
id: 1,
firstName: "a",
lastName: "b"
},
{
id: 2,
firstName: "x",
lastName: "y"
}
]
};
},
computed: {
msg() {
const selectedRow = this.selected[0];
return selectedRow ? `${selectedRow.firstName} ${selectedRow.lastName}` : "no data selected";
}
}
};
</script>