(vuejs) Array undefined with axios and quasar - javascript

I have a problem with an array that is undefined while in Vuejs devTool I see it full. Here is what I did with quasar:
When i click on my update button i want to display a q-card with input of my row. So i have make a request with axios and put response in array. But i have 'undefined' when i do a console.log() of my array.
<template>
<div>
<div class="q-pa-sm q-gutter-sm">
<q-dialog v-model="show_dialog" v-bind:programmeEdit="programmeEdit">
<q-card>
<q-card-section>
<div class="text-h6">Add new item!</div>
</q-card-section>
<q-card-section>
<div class="row">
<q-input v-model="programmeEdit.prg_libelle" label="prg_libelle"></q-input>
<q-input label="id"></q-input>
<q-input label="nom promotteur"></q-input>
<q-input label="date commercialistion"></q-input>
<q-input label="stock initial"></q-input>
<q-input label="nombre tranche"></q-input>
</div>
</q-card-section>
<q-card-actions align="right">
<q-btn flat label="OK" color="primary" v-close-popup #click="" ></q-btn>
</q-card-actions>
</q-card>
</q-dialog>
</div>
<q-table title="Programme" :filter="filter" :data="programme.data" :columns="columns" row-key="name">
<template v-slot:top-right>
<q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
<template v-slot:append>
<q-icon name="search" />
</template>
</q-input>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td key="prg_libelle" :props="props">{{ props.row.prg_libelle }}</q-td>
<q-td key="id" :props="props">{{ props.row.id }}</q-td>
<q-td key="nom_promotteur" :props="props">{{ props.row.act_libelle }}</q-td>
<q-td key="id_promotteur" :props="props">{{ props.row.id_promotteur }}</q-td>
<q-td key="date_commercialisation" :props="props">{{ props.row.tra_date_commercialisation }}</q-td>
<q-td key="stock_initial" :props="props">{{ props.row.tra_stock_initial }}</q-td>
<q-td key="nombre_tranche" :props="props">{{ props.row.nombre_tranche }}</q-td>
<q-td key="actions" :props="props">
<q-btn color="blue" label="Update" #click="getProgramme(props.row.id)" size=sm no-caps></q-btn>
<q-btn color="red" label="Delete" #click="deleteItem(props.row)" size=sm no-caps></q-btn>
</q-td>
</q-tr>
</template>
</q-table>
</div>
</template>
Vue.use(VueAxios, axios)
export default {
methods: {
},
data () {
return {
programmetoEdit:'',
show_dialog:false,
filter: '',
programme:{},
programmeEdit:{},
columns: [
{
name: 'prg_libelle',required: true, label: 'prg_libelle',align: 'left', field: 'prg_libelle' ,format: val => `${val}`, sortable: true },
{ name: 'id', align: 'center', label: 'id', field: 'id', sortable: true },
{ name: 'nom_promotteur', align: 'center',label: 'nom_promotteur', field: 'act_libelle', },
{ name: 'id_promotteur', align: 'center',label: 'id_promotteur', field: 'id_promotteur', },
{ name: 'date_commercialisation', align: 'center',label: 'date_commercialisation', field: 'tra_date_commercialisation', },
{ name: 'stock_initial', align: 'center',label: 'stock_initial', field: 'tra_stock_initial', },
{ name: 'nombre_tranche', align: 'center',label: 'nombre_tranche', field: 'nombre_tranche', },
{ name: "actions", label: "Actions", field: "actions"},
]
}
},
created() {
axios.get("http://localhost:80/api/programme")
.then(response =>this.programme=response)
.catch(error=>console.log(error))
},
methods: {
getProgramme($id){
axios.get("http://localhost:80/api/programme/"+$id)
.then(response => this.programmeEdit=response.data);
this.show_dialog= !this.show_dialog;
this.programmeEdit.id=this.programmetoEdit;
}
},
}
I get an undefined when I want to retrieve the query according to the id. I'm blocking and I don't know why.
thanks a lot :)

If you want to log it from your code (like in the .then promise, for example) you should do:
console.log(this.programmetoEdit);
Moreover, you are doing assignment in parallel of the job Axios is doing. Not after, as I guess you are expecting it to do.
You should drop all your stuff in the .then promise if you want it to happen after the this.programmeEdit=response.data part.
Like so (this will show the dialog WHILE loading the data/waiting for the API to respond):
getProgramme ($id) {
axios.get("http://localhost:80/api/programme/" + $id)
.then(response => {
this.programmeEdit=response.data;
this.programmeEdit.id=this.programmetoEdit;
});
this.show_dialog= !this.show_dialog;
}
Or like so (this will show the dialog AFTER loading the data/waiting for the API to respond):
getProgramme ($id) {
axios.get("http://localhost:80/api/programme/" + $id)
.then(response => {
this.programmeEdit=response.data;
this.programmeEdit.id=this.programmetoEdit;
this.show_dialog= !this.show_dialog;
});
}

Related

Action happening for all the items in v-for but I want to run the action on just the item I clicked on

I have an icon in the v-for loop and I want the action to be performed specifically to the one icon but it is happening for all the icons that are repeating because of v-for.
<template>
<div>
<tr
v-for="(randomData, randomIndex) in obj['randomData']"
:key="randomIndex"
class="random-table"
>
<td data-label="Activity Alert">
<el-popover
v-model="remindMeVisibility"
placement="left-start"
width="500"
trigger="manual"
class="popover-form"
>
<RemindMe />
<i
slot="reference"
class="el-icon-message-solid reminder-icon"
#click="remindMeVisibility = true"
></i>
</el-popover>
</td>
</tr>
</div>
</template>
<script>
export default {
data() {
return {
remindMeVisibility: false,
}
},
}
</script>
Here is a working example on how to have a specific popover edit per element for a given list.
<template>
<div>
<pre>{{ cityNames }}</pre>
<section>
<div v-for="city in cityNames" :key="city.id">
<span>City {{ city.name }}</span>
<el-popover v-model="city.popoverOpen" placement="top" width="160" class="popover">
<el-button slot="reference">Update visibility</el-button>
<p>Change the visibility of the City?</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" #click="toggleCityVisibility({ id: city.id, visibility: false })">
Hide it
</el-button>
<el-button type="primary" size="mini" #click="toggleCityVisibility({ id: city.id, visibility: true })">
Make visible
</el-button>
</div>
</el-popover>
</div>
</section>
</div>
</template>
<script>
export default {
data() {
return {
cityNames: [
{
id: 1,
name: 'beijing',
remindMeVisibility: false,
popoverOpen: false,
},
{
id: 2,
name: 'shanghai',
remindMeVisibility: false,
popoverOpen: false,
},
{
id: 3,
name: 'guangzhou',
remindMeVisibility: false,
popoverOpen: false,
}
]
};
},
methods: {
toggleCityVisibility({ id, visibility }) {
console.log('id', id, 'visibility', visibility)
this.targetedCity = this.cityNames.find(city => city.id === id)
this.targetedCity.remindMeVisibility = visibility
}
},
}
</script>
<style scoped>
.popover {
margin-left: 1rem;
}
</style>
Here, we do have a list of cities, and we want to toggle their visibility (remindMeVisibility).
The id in the list was given for the :key uniqueness + find it later on when editing the visibility of it.
I didn't expected popoverOpen to be required here, but it is (a global popover state is not feasible from what I've tried).
This is how it looks

how fixed column width of vuetify data table

I have a vuetify data table, I've set width for every column and I want to fixed column's width of my table but it has grown up because of their content and it doesn't matter what is the width of them.
how can fixed column's width?
<template>
<v-data-table
v-if="physicianAccountsLocalData"
:headers="headers"
:items="physicianAccountsLocalData"
hide-default-footer
class="data-table"
:items-per-page="-1"
>
<template #[`item.isActive`]="props">
<BaseSwitch
v-model="props.item.isActive"
class="switch-siam-table"
#change="changeModel($event, props)"
/>
</template>
<template #[`item.location`]="props">
<span
class="location"
:class="{'text-disable-state': !props.item.isActive}"
>
{{ props.item.location }}
</span>
</template>
<template #[`item.name`]="props">
<span
class="name"
:class="{'text-disable-state': !props.item.isActive}"
>
{{ props.item.name }}
</span>
</template>
</v-data-table>
</template>
<script>
data() {
return {
headers: [
{ text: 'فعال', value: 'isActive', sortable: false, width: '110px', align: 'right' },
{ text: 'نوع', value: 'location', sortable: false, width: '13%', align: 'start' },
{ text: 'نام', value: 'name', sortable: false, width: '200px' }
],
}
}
</script>

How to display a datatable through an accordion

I encountered some troubles creating an accordion table. I created an Accordion component and a Table component. While independant from each other it works perfectly fine but I can't get any table appear into accordion.
//js part of accordion component
import Table from "../Table/index.vue"
export default {
name: 'accordion',
components: { Table },
mounted () {
},
data(){
return {
items: [
{ id: "mc", title: "Medical Checkup", text: this.components.Table },
{ id: "ac", title: "Application connected", text:
this.components.Table },
{ id: "p", title: "Programs", text: this.components.Table },
{ id: "pl", title: "Pain list", text: this.components.Table }
]
}
}
}
//html part of accordion component
<div>
<div ref="list" class="list">
<transition-group class="flip-list" name="flip-list" ref="tg1"
tag="div">
<div v-for="(item,index) in items" :key="item.id" class="item">
<slot name="item" :class="{active:item.isOpen}" :item="item"
:index="index">
<v-expansion-panel id="exp1">
<v-expansion-panel-content>
<div slot="header" class="drop-target handle2">
<span>{{item.title}}</span>
</div>
<v-card>
<v-card-text>
<div slot="item">{{Table}}</div>
</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</slot>
</div>
</transition-group>
</div>
</div>
So, the point is : how can I make it so that a datatable appears into accordion ? Like when you click aon one of the titles and it appears instead of some text ?
Thanks a lot
Resolved!
In case of (if people encounter the same problem as I had), here is the code (html / js).
//html goes here
<div id="app">
<v-app id="inspire">
<v-data-table :headers="mainHeaders"
:items="mainItems"
item-key="title"
hide-actions
expand
class="elevation-1">
<template slot="items" scope="props">
<tr #click="props.expanded = !props.expanded">
<td class="text-xs">{{ props.item.title }}</td>
</tr>
</template>
<template slot="expand" scope="props">
<v-data-table :headers="subHeaders"
:items="subItems"
item-key="pain"
hide-actions
class="elevation-10">
<template slot="items" scope="props">
<td class="text-xs">{{ props.item.pain }}</td>
<td class="text-xs">{{ props.item.type }}</td>
</template>
</v-data-table>
</template>
</v-data-table> </v-app>
</div>
//js goes here
export default {
name: 'accordion-table',
mounted () {
},
data () {
return {
mainHeaders: [
{ text: 'Medical informations', value: 'title' }
],
mainItems: [
{ title: 'Medical Checkup' },
{ title: 'Application connected' },
{ title: 'Programs' },
{ title: 'Pain List' }
],
subHeaders: [
{ text: 'Pain', value: 'pain' },
{ text: 'Type', value: 'type' }
],
subItems: [
{ pain: 'Knee', type: '1' },
{ pain: 'Ankle', type: '2' },
{ pain: 'Back', type: '3' },
{ pain: 'Neck', type: '4' }
]
}
}
}
(I used random values)
Hope it helps some of you

Printing received JSON into a table

I have a VueJS template which includes a table and a function that sends out a request to the backend API with the specified key and then receives back a JSON response.
What I am having trouble is with writing the function so it takes the output it receives and then prints into the table.
JSON Sample:
{"driver_id":1,"driver_name":"{driver_first_name}, {driver_last_name}","driver_truck":"13","driver_trailer":"83","driver_status":"driving","has_violations":false},
{"driver_id":2,"driver_name":"{driver_first_name}, {driver_last_name}","driver_truck":"58","driver_trailer":"37","driver_status":"sleeping","has_violations":true},
{"driver_id":3,"driver_name":"{driver_first_name}, {driver_last_name}","driver_truck":"80","driver_trailer":"27","driver_status":"driving","has_violations":true},
Here is my code:
<template>
<b-container fluid>
<!--Search Controls-->
<b-row>
<b-col md="6" class="my-1">
<b-form-group horizontal label="Filter" class="mb-0">
<b-input-group>
<b-form-input v-model="filter" placeholder="Type to Search" />
<b-input-group-append>
<b-btn :disabled="!filter" #click="filter = ''">Clear</b-btn>
</b-input-group-append>
</b-input-group>
</b-form-group>
</b-col>
<b-col md="6" class="my-1">
<b-form-group horizontal label="Sort" class="mb-0">
<b-input-group>
<b-form-select v-model="sortBy" :options="sortOptions">
<option slot="first" :value="null">-- none --</option>
</b-form-select>
<b-form-select :disabled="!sortBy" v-model="sortDesc" slot="append">
<option :value="false">Asc</option>
<option :value="true">Desc</option>
</b-form-select>
</b-input-group>
</b-form-group>
</b-col>
<b-col md="6" class="my-1">
<b-form-group horizontal label="Sort direction" class="mb-0">
<b-input-group>
<b-form-select v-model="sortDirection" slot="append">
<option value="asc">Asc</option>
<option value="desc">Desc</option>
<option value="last">Last</option>
</b-form-select>
</b-input-group>
</b-form-group>
</b-col>
<b-col md="6" class="my-1">
<b-form-group horizontal label="Per page" class="mb-0">
<b-form-select :options="pageOptions" v-model="perPage" />
</b-form-group>
</b-col>
</b-row>
<!--Search Controls-->
<!-- Main table element -->
<b-table show-empty
stacked="md"
:items="items"
:fields="fields"
:current-page="currentPage"
:per-page="perPage"
:filter="filter"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
:sort-direction="sortDirection"
#filtered="onFiltered"
>
<template slot="truck_number" slot-scope="row">{{row.value.driver_truck}}</template>
<template slot="trailer_number" slot-scope="row">{{row.value.driver_trailer}}</template>
<template slot="violation_date" slot-scope="row">{{row.value.violation_date}}</template>
<!-- View Specific Violation -->
<template slot="actions" slot-scope="row">
<b-button #click="getSpecificViolation(logbook_id)" id="view_specific_violation">View Violation</b-button>
</template>
</b-table>
<b-row>
<b-col md="6" class="my-1">
<b-pagination :total-rows="totalRows" :per-page="perPage" v-model="currentPage" class="my-0" />
</b-col>
</b-row>
</b-container>
</template>
<script>
export default {
name: 'List of Violations',
data () {
return {
items: items,
fields: [
{ key: 'truck_number', label: 'Truck Number', sortable: true, 'class': 'text-center' },
{ key: 'trailer_number', label: 'Trailer Number', sortable: true, 'class': 'text-center' },
{ key: 'violation_date', label: 'Date of Violation' },
{ key: 'actions', label: 'Actions' }
],
currentPage: 1,
perPage: 5,
totalRows: items.length,
pageOptions: [ 5, 10, 15 ],
sortBy: null,
sortDesc: false,
sortDirection: 'asc',
filter: null,
}
},
},
computed: {
sortOptions () {
return this.fields
.filter(f => f.sortable)
.map(f => { return { text: f.label, value: f.key } })
}
},
created() {
this.id = this.$route.params.id;
},
methods: {
onFiltered (filteredItems) {
// Trigger pagination to update the number of buttons/pages due to filtering
this.totalRows = filteredItems.length
this.currentPage = 1
}
navigate() {
router.go(-1);
}
//Send Request all Violations for Driver_ID
axios.post('http://localhost:3030/api/allViolations/driverID',
this.driver_id, // the data to post
{ headers: {
'Content-type': 'application/x-www-form-urlencoded',
}
}).then(response => ....???); //print api json response
}
}
</script>
First of all, your code structure is disrupted. You shouldn't define computed,created and methods functions outside the export default module.
I created a sandbox for you just to rearrange the code and assign the value of response to items variable.
.then(response => (this.items = response.data));
If i assume correctly you are using Bootstrap-Vue plugin. After obtaining the items object you can follow the documentation from here
First of all, your initial value for items in data should be [] (an empty array).
After that, pretty much all you should need to do is set this.items = response.data when you get the JSON back. Although the code you pasted seems to be bad (the axios.post call is directly under methods).

Bootstrap Vue Dynamic table templating

I am working with Bootstrap Vue JS table component to create a datatable:
https://bootstrap-vue.js.org/docs/components/table
I am new to VueJS and am uncertain on how to approach this problem which makes searching for a solution even more complicated.
I use an API endpoint to return JSON data:
{
"options":{
"filter":false
},
"fields":[
{
"key":"id",
"label":"Id",
"editLink":false,
"display":true,
"sortable":true,
"class":"shrink"
},
{
"key":"name",
"label":"Name",
"editLink":true,
"display":true,
"sortable":true
}
],
"data":[ ]
}
Here is my table template:
<b-table striped hover bordered foot-clone class="table-sm"
:items="users" :fields="displayedFields" :per-page="perPage" :current-page="currentPage" :filter="filter"
#filtered="onFiltered"
>
<template v-for="(field, index) in fields">
<template slot="{{field.key}}" slot-scope="row" v-if="field.editLink">
<router-link :to="'/user/' + row.item.id" v-bind:key="index"></router-link>
</template>
</template>
<template slot="status" slot-scope="row">
<toggle-button :width="36" :height="18" v-model="row.status" :labels="false" :colors="{checked: '#00FF00', unchecked: '#FF0000', disabled: '#CCCCCC'}"/>
</template>
</b-table>
The first template tag is an attempt from a wild guess. I want to be able to conditionally select a table for a column from the fields config. You can see in my attempt that I want to put a RouterLink when the field's config editLink is true.
How can I get this done?
If you're using version 2.0.0 or newer of bootstrap-vue you need to change the slot names as
they've changed, and the old vue slot has also been deprecated in favor for v-slot.
I changed the accepted answers fiddle to work with the new naming and v-slot
new Vue({
el: "#app",
data: {
fields: [{
key: "id",
label: "Id",
colType: "span"
}, {
key: "name",
label: "Name",
colType: "button"
}, {
key: "uhh",
label: "uhh..",
colType: "idk"
}],
items: [{
id: 0,
name: "Test 0"
}, {
id: 1,
name: "Test 1"
}, {
id: 2,
name: "Test 2"
}]
}
});
<link href="https://unpkg.com/bootstrap#4.3.1/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.0.0/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.0.0/dist/bootstrap-vue.js"></script>
<div id="app">
<b-table :items="items" :fields="fields">
<template v-for="(field, index) in fields" v-slot:[`cell(${field.key})`]="data">
<div v-if="field.colType === 'button'">
<h5>{{data.item.name}}</h5>
<b-button>Am Button</b-button>
</div>
<div v-else-if="field.colType === 'span'">
<h5>{{data.item.name}}</h5>
<span>Am Span</span>
</div>
<div v-else>
<h5>{{data.item.name}}</h5>
Am Confused
</div>
</template>
</b-table>
</div>
Here's a jsfiddle showing dynamic columns with a b-table:
https://jsfiddle.net/nardnob/wvk6fxgt/
new Vue({
el: "#app",
data: {
fields: [{
key: "id",
label: "Id",
colType: "span"
}, {
key: "name",
label: "Name",
colType: "button"
}, {
key: "uhh",
label: "uhh..",
colType: "idk"
}],
items: [{
id: 0,
name: "Test 0"
}, {
id: 1,
name: "Test 1"
}, {
id: 2,
name: "Test 2"
}]
}
});
<div id="app">
<b-table :items="items" :fields="fields">
<template v-for="(field, index) in fields" :slot="field.key" slot-scope="data">
<div v-if="field.colType === 'button'">
<h5>{{data.item.name}}</h5>
<b-button>Am Button</b-button>
</div>
<div v-else-if="field.colType === 'span'">
<h5>{{data.item.name}}</h5>
<span>Am Span</span>
</div>
<div v-else>
<h5>{{data.item.name}}</h5>
Am Confused
</div>
</template>
</b-table>
</div>

Categories