Array of Objects Data wont bind to Vuetify Data Table? - vue.js

I have a Vuetify data table which takes the headers as an array of objects returned in the component and the data (:items) is bound to an array also returned in the component. This array is populated with Firestore data which is there, because I can console.log it.
The issue is that the data table is empty, and contains no data in the body at all.
Could this be caused because my items array contains more data points then I have headers in my table?
Vuetify Component
<template>
<v-card>
<v-card-title>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
></v-text-field>
</v-card-title>
<v-data-table
:headers="headers"
:items="items"
:search="search"
></v-data-table>
</v-card>
</template>
Component Script
<script>
/* eslint-disable */
import firestore from '/firebase.js';
export default {
data() {
return {
search: '',
items: [],
headers: [
{
text: 'ID',
align: 'start',
sortable: true,
value: 'name',
},
{ text: 'Date Created', value: 'Date Created' },
{ text: 'Date Finished', value: 'Date Finished' }
],
show: false,
};
},
name: "Home",
methods: {
getData() {
firestore.collection("itemStore")
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
var itemData = doc.data();
this.items.push({
id: itemData.incId,
dateCreated: itemData.dateCreated,
dateFinished: itemData.dateFinished,
email: itemData.email
});
console.log(this.items);
});
});
}
},
mounted() {
this.getData();
}
};
</script>

The value attribute of your headers collection has to correspond with the keys of your items. So in your case it should look like this:
headers: [
{
text: 'ID',
align: 'start',
sortable: true,
value: 'id',
},
{
text: 'Date Created',
value: 'dateCreated'
},
{
text: 'Date Finished',
value: 'dateFinished'
}
]

Related

Cannot read properties of undefined on formatter, but data is showing fine

I have a bootstrap table that shows a list of appliances. I am importing my data with Axios and for this specific table I am outputting data from two database tables, so I have one object which is called applianceReferences which stores another object called activeAppliances.
Not sure if it is relevant for this question, but just so you know.
Before talking about the problem, let me just post the whole code and below I will talk about the section that is giving me issues.
<template>
<b-container class="my-2">
<b-card v-if="showTable" class="ml-4 mr-4">
<b-table
search-placeholder="search"
:filter-included-fields="fields.map(f => f.key)"
include-filter
:items="applianceReferences"
:fields="fields"
/>
</b-card>
</b-container>
</template>
<script>
import {applianceService} from "#/services/appliance";
import CommonCollapsible from "#/components/common/CommonCollapsible";
import moment from 'moment';
export default {
components: { CommonCollapsible, CommonTable },
props: {
ownerId: String,
ownerType: String,
showDocuments: Boolean,
goToAppliances: "",
importAppliances: ""
},
data() {
return {
applianceReferences: [],
showTable: true
}
},
computed: {
fields() {
return [
{
key: 'referenceName',
label: this.$t('referenceName'),
sortable: true
},
{
key: 'activeAppliance.type',
label: this.$t('type'),
sortable: true,
},
{
key: 'activeAppliance.brandName',
label: this.$t('brand'),
sortable: true
},
{
key: 'activeAppliance.purchaseDate',
label: this.$t('purchaseDate'),
sortable: true,
template: {type: 'date', format: 'L'}
},
{
key: 'activeAppliance.warrantyDuration',
label: this.$t('warrantyDuration'),
sortable: true,
formatter: (warrantyDuration, applianceId, appliance) =>
this.$n(warrantyDuration) + ' ' +
this.$t(appliance.activeAppliance.warrantyDurationType ?
`model.appliance.warrantyDurationTypes.${appliance.activeAppliance.warrantyDurationType}` :
''
).toLocaleLowerCase(this.$i18n.locale),
sortByFormatted: (warrantyDuration, applianceId, appliance) =>
appliance.activeAppliance.warrantyDurationType === 'YEARS' ? warrantyDuration * 12 : warrantyDuration
},
{
key: 'activeAppliance.purchaseAmount',
label: this.$t('amount'),
sortable: true,
template: {
type: 'number', format: {minimumFractionDigits: '2', maximumFractionDigits: '2'},
foot: sum
}
},
{
key: 'actions',
template: {
type: 'actions',
head: [
{
text: 'overviewOfAppliances',
icon: 'fas fa-fw fa-arrow-right',
action: this.createAppliance
},
{
icon: 'fas fa-fw fa-file-excel',
action: this.importAppliance,
tooltip: this.$t('importAppliances'),
}
],
cell: [
{
icon: 'fa-trash',
variant: 'outline-danger',
action: this.remove
},
]
}
}
]
},
},
methods: {
load() {
Object.assign(this.$data, this.$options.data.apply(this));
this.applianceReferences = null;
applianceService.listApplianceReferences(this.ownerId).then(({data: applianceReferences}) => {
this.applianceReferences = applianceReferences;
this.applianceReferences.forEach( reference => {
applianceService.listAppliances(reference.id).then(result => {
this.$set(reference, 'appliances', result.data);
this.$set(reference, 'activeAppliance', result.data.find(appliance => appliance.active))
this.loaded = true
})
})
}).catch(error => {
console.error(error);
})
},
createAppliance(){
this.goToAppliances()
},
importAppliance(){
this.importAppliances()
},
},
watch: {
ownerId: {
immediate: true,
handler: 'load'
}
},
}
</script>
Okay, so the error occurs in this specific property:
{
key: 'activeAppliance.warrantyDuration',
label: this.$t('warrantyDuration'),
sortable: true,
formatter: (warrantyDuration, applianceId, appliance) =>
this.$n(warrantyDuration) + ' ' +
this.$t(appliance.activeAppliance.warrantyDurationType ?
`model.appliance.warrantyDurationTypes.${appliance.activeAppliance.warrantyDurationType}` :
''
).toLocaleLowerCase(this.$i18n.locale),
sortByFormatted: (warrantyDuration, applianceId, appliance) =>
appliance.activeAppliance.warrantyDurationType === 'YEARS' ? warrantyDuration * 12 : warrantyDuration
},
What I am basically doing here is combining two values from the object: warrantyDuration and warrantyDurationType and putting them in one single row in my bootstrap table.
The problem is that this is giving me an error: Cannot read properties of undefined (reading 'warrantyDurationType'
Yet the data actually outputs normally.
So what exactly does it want me to do?
I tried wrapping a v-if around the table to make sure that the application checks if the data exist before outputting it, but this does not solve the issue.
<div v-if="applianceReferences && applianceReferences.activeAppliance">
<b-card v-if="showTable" class="ml-4 mr-4">
<common-table
search-placeholder="search"
:filter-included-fields="fields.map(f => f.key)"
include-filter
:items="applianceReferences"
:fields="fields"
/>
</b-card>
</div>
Last, just to give you a full overview, my array looks like this:
Any ideas?

The state (products) dont render in the v-data-table from vuetify

Im get the products state in my computed well , but when i add the products into the table i get ann error.
the products came from api call, What can I do to make the information appear?
the error is : [Vue warn]: Invalid prop: type check failed for prop "items". Expected Array, got Object
<template>
<v-card>
<v-card-title>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
></v-text-field>
</v-card-title>
<v-data-table
:headers="headers"
:items="products"
:search="search"
></v-data-table>
</v-card>
</template>
<script>
export default {
name: "products",
data() {
return {
search: "",
headers: [
{
text: "Year",
align: "start",
filterable: true,
value: "year",
},
{ text: "Item", value: "item" },
{ text: "Element", value: "element" },
{ text: "Value", value: "value" },
{ text: "Unit", value: "unit" },
{ text: "Area Code", value: "areacode" },
{ text: "Area", value: "area" },
],
};
},
created() {
this.$store.dispatch("loadProducts");
},
computed: {
products() {
return this.$store.state.products
},
},
};
</script>

Search in vuetify datatable (server side)

I'm using vuetify datatables with server side in my app.
Pagination and sorting works fine but I have problem with search input - when I write something in input, new requests dont't send to api.
I found solution with pagination.sync in options but when I try it I get an error in the console:
[BREAKING] 'pagination' has been removed, use 'options' instead. For
more information, see the upgrade guide
https://github.com/vuetifyjs/vuetify/releases/tag/v2.0.0#user-content-upgrade-guide
My code is here:
<template>
<v-container fluid>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
></v-text-field>
<v-data-table
:items="usersList"
:headers="headers"
sort-by="name"
:sort-desc="false"
:options.sync="options"
:server-items-length="totalUsers"
:search="search"
:loading="loading"
loading-text="Ładowanie..."
class="elevation-0"
></v-data-table>
</v-container>
</template>
<script>
export default {
data: () => ({
totalUsers: 0,
usersList: [],
search: "",
loading: true,
options: {},
headers: [
{ text: 'Nazwa użytkownika', value: 'name' },
{ text: 'Adres e-mail', value: 'email' },
{ text: 'Opcje', value: 'actions', sortable: false },
]
}),
watch: {
options: {
handler () {
this.getUsers();
},
deep: true
},
},
mounted () {
this.getUsers();
},
methods: {
getUsers() {
this.loading = true;
userService.getAll(this.options).then(data => {
if (data.status == "success") {
this.usersList = data.items;
this.totalUsers = data.total;
} else {
console.log("Nie udało się pobrać użytkowników.");
}
this.loading = false;
});
},
}
};
</script>

How to set dynamic v-model for input and set value to this v-model in Vue 2

I have a component for creating dynamic input fields. I have a prop - fields.
fields: [
{
label: 'Question Text',
placeholder: 'Enter Text',
isRequired: true,
editable: true,
name: 'question',
value: '123',
},
{
label: 'Button Text',
placeholder: 'Enter Text',
isRequired: true,
editable: true,
name: 'button',
value: '',
},
],
Than I pass this to component SettingsViewFields.vue
<template>
<div>
<e-form-group v-for="(field, index) in fields" :key="index" :error="getInputError[field.name]">
<template v-slot:label>
{{ field.label }}
</template>
<e-textarea
v-model="form[field.name]"
:name="field.name"
size="small"
#input="onInput($event, field.name)"
></e-textarea>
</e-form-group>
</div>
</template>
<script>
export default {
name: 'SettingsViewFields',
props: {
fields: {
type: Array,
default: () => [],
},
},
data: () => ({
form: [],
}),
};
</script>
I want that reactive data for input calls from field.name that the reactive data will be form: {question: '', button: ''} But the problem I have to set correct value for input, but if I set field.name the value will be not correct because for first input it's value: '123'.
You can't Change the data passed by the parent component directly, when you receive the prop data from parent that you want update, you can make a copy of this,eg
computed: {
fieldsCopy: function () {
return this.fields
},
}
and use fieldsCopy in your template, that may work.
if you also want to pass the updated data to parent , use emit.

nuxt.js fetching data to vuetify table

i am facing problem on fetching data inside vuetify table, it's not showing any data in side table.
MY Laravel API
Route::get('/businesslist',
'BusinessController#userlist')->name('businesslist');
Laravel API Controller
public function businesslist() {
$businesslist = Business::paginate(2)->toJson(JSON_PRETTY_PRINT);
return response($businesslist);
}
}
Nuxt Code
<template>
<v-card>
<v-card-title>
Nutrition
<v-spacer></v-spacer>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
></v-text-field>
</v-card-title>
<v-data-table
:headers="headers"
:items="registerlist"
:search="search"
></v-data-table>
</v-card>
</template>
<script>
export default {
data () {
return {
search: '',
headers: [
{ text: 'SL,No', value: '' },
{ text: 'Name', value: 'name' },
{ text: 'Mobile ', value: 'mobile_number' },
{ text: 'Location ', value: 'location' },
{ text: 'Join Date ', value: 'registration_date' },
{ text: 'Renewal Date ', value: 'registration_renewal_date' },
],
registerlist: [
],
}
axios.get('/Businessregisterlist')
.then(res => this.registerlist = res.data.registerlist)
},
}
</script>
Firstly, you have to call API within a Function like this:
<script>
export default {
data() {
return {
list: []
}
},
methods: {
callAPI() {
axios.get('/', then(function(res){
this.list = res.data.registerList;
}))
}
},
mounted(){
this.callAPI(); // if you need that List on load then you can use mounted() otherwise that function will call during event.
}
}
</script>
Here, inside then() I think it's better to use function(). Because if you use function then it will indicate this Object. So, we can easily access all the Object Properties (Like: data(), methods() etc.).