I´m trayin integrate datatable in my component vue. For this i´m using this library:
https://jamesdordoy.github.io/
i´m install in my proyect, i has configured it, created my component and include in my view, but returned me this message:
Invalid prop: type check failed for prop "data". Expected Object, got Array
my component it´s:
<template>
<div>
<div class="row justify-content-center w-100">
<data-table :data="data" :columns="columns" #on-table-props-changed="reloadTable"></data-table>
</div>
</div>
</template>
<script>
export default {
data() {
return {
url: "/admin/vue/getAllUsers",
data: {},
tableProps: {
search: '',
length: 10,
column: 'id',
dir: 'asc'
},
columns: [
{
label: 'ID',
name: 'id',
orderable: true,
},
{
label: 'Name',
name: 'name',
orderable: true,
},
{
label: 'Email',
name: 'email',
orderable: true,
},
]
}
},
created() {
this.cargar(this.url);
},
methods:{
cargar(url = this.url, options = this.tableProps){
axios.get(url, { params: options })
.then((response) => {
this.data = response.data;
})
.catch((error) => console.error(error));
},
reloadTable(tableProps) {
this.cargar(this.url, tableProps);
}
},
}
</script>
i was trayed with response.data[0] the error disappear but my table it´s empty, i don´t know that i´m doing wrong.
In my controller i have this:
return User::all();
i´m working with laravel 8
thanks for help
you should pass props :items = "data" instead of :data = "data"
Related
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?
I created a select2 wrapper in vue3 with options API everything working fine but the problem is that when getting values from calling API it's not selected the default value in the select2 option. but when I created a static array of objects it does. I don't know why it's working when it comes from the API
Parent Component
Here you can I passed the static options array in options props and my selected value is 2 and it's selected in my Select2 component, but when passed formattedCompanies it's not which is the same format as the static options array then why is not selected any reason here..?
<template>
<Form #submitted="store()" :processing="submitting">
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label>Company Name</label>
<Select2
:options="options"
v-model="selected"
placeholder="Select Company"
/>
<ValidationError :errors="errors" error-key="name" />
</div>
</div>
</div>
</Form>
</template>
<script>
import Form from "#/components/Common/Form";
import Select2 from "#/components/Common/Select2";
export default {
components: {
Select2,
Form
},
data() {
return {
selected : 2,
companies : [],
options: [ // static array
{ id: 1, text: 'hello' },
{ id: 2, text: 'hello2' },
{ id: 3, text: 'hello3' },
{ id: 4, text: 'hello4' },
{ id: 5, text: 'hello5' },
],
}
},
mounted() {
this.getAllMedicineCompanies()
},
computed:{
formattedCompanies() {
let arr = [];
this.companies.forEach(item => {
arr.push({id: item.id, text: item.name})
});
return arr;
}
},
methods: {
getAllMedicineCompanies(){
axios.get('/api/get-data?provider=companies')
.then(({ data }) => {
this.companies = data
})
},
}
}
</script>
Select2 Component
Here is what my select2 component look like, did I do anything wrong here, please anybody help me
<template>
<select class="form-control">
<slot/>
</select>
</template>
<script>
export default {
name: "Select2",
props: {
options: {
type: [Array, Object],
required: true
},
modelValue: [String, Number],
placeholder: {
type: String,
default: "Search"
},
allowClear: {
type: Boolean,
default: true
},
},
mounted() {
const vm = this;
$(this.$el)
.select2({ // init select2
data: this.options,
placeholder: this.placeholder,
allowClear: this.allowClear
})
.val(this.modelValue)
.trigger("change")
.on("change", function () { // emit event on change.
vm.$emit("update:modelValue", this.value);
});
},
watch: {
modelValue(value) { // update value
$(this.$el)
.val(value)
.trigger("change");
},
options(options) { // update options
$(this.$el)
.empty()
.select2({data: options});
},
},
destroyed() {
$(this.$el)
.off()
.select2("destroy");
}
}
</script>
Probably when this Select2 mounted there is no companies. It is empty array after that it will make API call and it it populates options field and clear all options.
Make:
companies : null,
Change it to
<Select2
v-if="formattedCompanies"
:options="formattedCompanies"
v-model="selected"
placeholder="Select Company"
/>
It should be like this:
<template>
<Form #submitted="store()" :processing="submitting">
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label>Company Name</label>
<Select2
v-if="formattedCompanies"
:options="formattedCompanies"
v-model="selected"
placeholder="Select Company"
/>
<ValidationError :errors="errors" error-key="name" />
</div>
</div>
</div>
</Form>
</template>
<script>
import Form from "#/components/Common/Form";
import Select2 from "#/components/Common/Select2";
export default {
components: {
Select2,
Form
},
data() {
return {
selected : 2,
companies : null,
options: [ // static array
{ id: 1, text: 'hello' },
{ id: 2, text: 'hello2' },
{ id: 3, text: 'hello3' },
{ id: 4, text: 'hello4' },
{ id: 5, text: 'hello5' },
],
}
},
mounted() {
this.getAllMedicineCompanies()
},
computed:{
formattedCompanies() {
let arr = [];
this.companies.forEach(item => {
arr.push({id: item.id, text: item.name})
});
return arr;
}
},
methods: {
getAllMedicineCompanies(){
axios.get('/api/get-data?provider=companies')
.then(({ data }) => {
this.companies = data
})
},
}
}
</script>
The problem was that my parent component and Select2 component mounted at the same time that's why my computed value is not initialized so the selected value is not selected in the option,
problem solved by setTimeOut function in mounted like this
Select2 Component
<script>
mounted() {
const vm = this;
setTimeout(() => {
$(this.$el)
.select2({ // init select2
data: this.options,
placeholder: this.placeholder,
allowClear: this.allowClear
})
.val(this.modelValue)
.trigger("change")
.on("change", function () { // emit event on change.
vm.$emit("update:modelValue", this.value);
});
}, 500)
},
</script>
So I have this itemlist.vue file
<div>
<div>
<ag-table
style=" height: 650px;"
class="ag-theme-balham"
:column-defs="columnDefs"
:row-data="rowData"
/>
</div>
</div>
</template>
<script>
import AgTable from "../components/AgTable";
import editRenderer from "../components/AgGridRenderers/editDeleteRenderer.vue";
export default {
components: {
AgTable
},
data: () => ({
users: [],
columnDefs: null,
rowData: null,
editR: editRenderer
}),
mounted () {
this.columnDefs = [
{ headerName: "Name", field: "name", sortable: true, filter: true },
{ headerName: "e-Mail", field: "email", sortable: true, filter: true },
{ headerName: "Contact", field: "contact", sortable: true, filter: true },
{ headerName: "Contact", field: "contact", sortable: true, filter: true, cellRenderer: editRenderer }
];
this.rowData = [
{ name: "Robin Sharma", email: "robin#sharma.com", contact: 8508035076 },
{ name: "Amish Tripathi", email: "amish#tripathi.com", contact: 9250035054 },
{ name: "Zig Ziglar", email: "zig#ziglar.com", contact: 9206635030 },
{ name: "Paulo Coelho", email: "paolo#coelho.com", contact: 7288012335 }
];
},
methods: {
loadUsers () {
// console.log("Loading Users from api.");
}
}
};
</script>
And index.vue file for Ag grid table as
<template>
<div>
<ag-grid-vue
style=" height: 650px;"
class="ag-theme-balham"
:column-defs="_props.columnDefs"
:row-data="_props.rowData"
:framework-components="frameworkComponents"
/>
</div>
</template>
<script>
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-balham.css";
import { AgGridVue } from "ag-grid-vue";
import editRenderer from "../AgGridRenderers/editDeleteRenderer.vue";
export default {
components: {
AgGridVue
},
props: [
"column-defs", "row-data"
],
data: () => ({
frameworkComponents: {
editRenderer
}
}),
mounted () {
console.log(this._props.columnDefs, this._props.rowData);
}
};
</script>
And editrenderer.vue file as:
<template>
<div>
<span>
<button #click="sayHi"> Edit Item </button>
</span>
</div>
</template>
<script>
export default {
created () {
console.log("Hello from Edit");
},
methods: {
sayHi () {
alert("Hi");
}
}
};
</script>
And all I am getting in the DOM is empty edit-renderer tags
Doesn't AgGrid support cellRenderers in Vue Js?
In the end the imported component appears as a vue component in the Dom if used separately as a common Dom element. Does that mean we explicitly have to compile it somehow? I also tried using setTimeOut before initializing columnDefs and rowData where AgTable is used. but still it doesn't show anything in the table.
Ok, so what I did was add some missing properties to ag-grid-vue element such as grid-options, context and grid-ready, and add refresh function to the renderer component, and convert all related components from simple "export default{" to "export default Vue.extends({".
I think this problem was resolved.
Though, I am getting 'this is undefined' error now.
Ag-grid should clarify which parameters are compulsory other than rowData and colDefs with their purpose.
I made a data table with vue vuetify and I fetch my data from my api server.
In my table, everything is display except boolean.
Can you help me to see clearer
Table component
<template>
<v-data-table
:headers="headers"
:items="fixture"
:items-per-page="5"
class="elevation-10"
>
</v-data-table>
</template>
<script>
export default {
name: 'my_fixtures',
props: ['fixture'],
data () {
return {
headers: [
{ text: 'name',value: 'name'},
{ text: 'State', value: 'on' },
{ text: 'Group', value: 'group' },
{ text: 'Recipe', value: 'recipe' },
{ text: 'start', value: 'startDate' },
{ text: 'end', value: 'endDate' },
{ text: 'Action', value: 'action' },
],
items: this.fixtures
}
}
}
</script>
In the object that I receive , the key 'on' is a Boolean.
I have all display , but nothing in the 'on' column
and this is what I do with props
<template>
<v-container>
<my_fixtures v-bind:fixture="fixtures"></my_fixtures>
<router-view></router-view>
</v-container>
</template>
<script>
import my_fixtures from "./greenhouse/fixtures";
export default {
name: "my_client",
data: function (){
return {fixtures: []}
},
components: {my_fixtures},
mounted() {
http.get('fixture/client')
.then(result => {
this.fixtures = result;
})
.catch(error => {
console.error(error);
});
}
}
</script>
Process and print data using methods.
try this.
<td class="text-xs-right">{{ computedOn(props.fixture.on) }}</td>
export default {
methods: {
computedOn (value) {
return String(value)
}
}
}
UPDATE
Modifying original data due to vuetify bug
https://github.com/vuetifyjs/vuetify/issues/8554
export default {
mounted() {
http.get('fixture/client')
.then(result => {
this.fixtures = result.map(value => {
value.on = String(value.on)
})
})
.catch(error => {
console.error(error);
});
}
}
I am using MDBootstrap for Vue js, the way to use datatable is to to use prop :data="data" which I calling here tableData and I have columns ready but I need to mutate the rows inside my object,
I couldn't do that with rows:this.data or rows:data which is where I handle getting data from my server.
How can I handle this and mutate rows inside tableData ?
<template>
<div class="container-fluid">
<ProgressSpinner v-if="isLoading"/>
<mdb-datatable :data="tableData" striped bordered/>
</div>
</template>
<script>
import ProgressSpinner from './Preloader'
import DataTable from 'vue-materialize-datatable'
import { mdbDatatable } from 'mdbvue'
export default {
name: 'Companies',
data: () => ({
data: [],
tableData: {
columns: [
{ label: 'ID', field: 'id', sort: 'asc' },
{ label: 'Name', field: 'name' },
{ label: 'Phone', field: 'phone', sort: 'asc' },
{ label: 'Email', field: 'email', sort: 'asc' },
{ label: 'City', field: 'city', sort: 'asc' },
{ label: 'Join Date', field: 'joined_at' }
],
rows: []
},
}),
created() {
this.$store
.dispatch('allCompanies')
.then(() => {
this.data = this.$store.getters.getAllCompanies
})
.catch(() => {
this.customerErrors = this.$store.getters.customerError
})
},
computed: {
isLoading() {
return this.$store.getters.customersAreLoading
},
},
components: {
ProgressSpinner,
datatable: DataTable,
mdbDatatable
},
mounted() {
$('.container-fluid').bootstrapMaterialDesign()
}
}
</script>
You should assign the value to tableData.rows when available.
this.$store
.dispatch('allCompanies')
.then(() => {
this.tableData.rows = this.$store.getters.getAllCompanies
})