How to call method in loop using vuejs - vue.js

I already call method in v-for, it works. But I get
[Vue warn]: You may have an infinite update loop in a component render function.
How to solve this?
This is my code:
<tr v-for="(item,index) in all_data" :key="index">
<td>{{ item.name }}</td>
<td colspan="2">{{ toMakeLocalString(item.data_trx.total_penjualan) }}</td>
<td>{{ roundDataPercentPerline(item.data_trx.total_penjualan,all_data_trx.penjualan) }}</td>
{{ resetVal() }}
<template v-for="(itemBodyJum,indexBodyJum) in arrHeader">
<template v-if="itemBodyJum == item.data_provider[incrementI].denom">
<td :key="indexBodyJum+item.data_provider[incrementI].jumlah_trx">{{ toMakeLocalString(item.data_provider[incrementI].jumlah_trx) }}</td>
{{ incVal(incrementI) }}
</template>
<template v-else>
<td :key="indexBodyJum+index">0</td>
</template>
</tr>
My method:
incVal(val, flagcond) {
console.log(this.flagInc+'---1')
if(this.flagInc == false) {
this.flagInc = true
console.log(this.flagInc+'---2')
this.incrementI = val + 1
}
},
resetVal() {
this.flagInc = false
this.incrementI=0
}

Your problem is that you change the incrementI variable during the V-FOR. Try to use something else instead - e.g. indexBodyJum or indexBodyPen.

Related

How to get rid of the Brackets from fetched Nested Array

Good day to you guys.
May I seek your help.
I'm stuck figuring out on how to get rid of the Brackets and Separate each data from my nested array. Here's my code:
<template>
<v-data-table
:headers="headers"
:items="teams"
>
<template v-slot:body="{ items }">
<tbody>
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.business_Units }}</td>
<td>
<v-icon small class="mr-2" #click="editRole(item)">
mdi-pencil
</v-icon>
</td>
<td>{{ item.status | boolean }}</td>
</tr>
</tbody>
</template>
</v-data-table>
</template>
<script>
export default {
//..... chunk of my code on how to request from the api
created() {
SparrowService.getTeams()
.then((response) => {
this.loading = false;
this.teams = response.data;
})
.catch((error) => {
console.log(error.response);
});
},
};
</script>
item.business_Units is the array, so you need to take some action to join to the string.
Refer to Array.join()
...
<td>{{ item.business_Units.join(", ") }}</td>
...

Target a specific cell background color in a v-for loop

With vuejs I fill a table with some data with this code :
<tr v-for="droit in listedroit">
<td>{{ droit.id_u }}</td>
<td>{{ droit.role }}</td>
<td>{{ droit.id_e }}</td>
<td>{{ droit.droits }}</td>
<td v-bind:style="{ 'background-color': statusColor }">STATUS</td>
</tr>
statusColor is computed in my app.js and returned to the template.
Some rows need a red cell, others a green one (I check if the rights are RO(green) or RW(red)).
The problem is I failed to target a specific cell of a row, and if I set statusColor to 'red', the whole column is red.
How can I achieve this ?
Thanks a lot for your help.
You can use a method instead of a computed property
<template>
<tr v-for="droit in listedroit">
<td>{{ droit.id_u }}</td>
<td>{{ droit.role }}</td>
<td>{{ droit.id_e }}</td>
<td>{{ droit.droits }}</td>
<td v-bind:style="{ 'background-color': statusColor(droit.rights) }">STATUS</td>
</tr>
</template>
export default{
methods: {
statusColor(rights){
if(rights === 'RO'){
return 'green';
} else {
return 'red';
}
}
}
}

How can I add a click event to the v-data-table?

I want to call the editItem function when the table row is clicked. Current what happens is I click on the table row and it doesn't display the details page. Yet when I put this click event on a particular table data the editItem function gets called. How can I make this same function to be called on the table row itself?
Here in my code I have tried using the the v-data-table template and slot and included the click event on the row but it is not working either
<template slot="items" slot-scope="props">
<tr #click="editItem(item), selected = item.id">
<td>{{ props.item.member }}</td>
<td>{{ props.item[1] }}</td>
<td>{{ props.item[2] }}</td>
<td>{{ props.item[3] }}</td>
<td>{{ props.item[4] }}</td>
<td>{{ props.item[5] }}</td>
<td>{{ props.item[6] }}</td>
<td>{{ props.item[7] }}</td>
<td>{{ props.item[8] }}</td>
<td>{{ props.item[9] }}</td>
<td>{{ props.item[10] }}</td>
<td>{{ props.item[11] }}</td>
<td>{{ props.item[12] }}</td>
<td>{{ props.item[13] }}</td>
</tr>
</template>
I expect that when the row is clicked, the editItem function is called
I found a way around it using #click:row
<v-data-table :headers="headers" :items="desserts" :items-per-page="5"
class="elevation-1" #click:row="handleClick">
</v-data-table>
The handleClick function returns a value of the clicked item so I call the method I want to act upon the value within the handleClick method. I also manually highlighted the clicked row since I didn't find a Vuetify way of doing so.
An example of the handleClick method is here:
handleClick(value) {
this.highlightClickedRow(value);
this.viewDetails(value);
},
You can also access the clicked row using event.target. Example is here
highlightClickedRow(value) {
const tr = value.target.parentNode;
tr.classList.add('highlight');
},
I got another solution with highlighting.
Because Anjayluh's idea was not working for me.
in Vuetify 2.0.0
template
<v-data-table
:headers="headers"
:items="desserts"
:class="[item.selected && 'selected']"
#click:row="handleClick"
/>
...
</v-data-table>
and the script method
handleClick(row) {
// set active row and deselect others
this.desserts.map((item, index) => {
item.selected = item === row
this.$set(this.desserts, index, item)
})
// or just do something with your current clicked row item data
console.log(row.sugar)
},
and a style
.selected {
background-color: red
}
This solutions is the best for, maybe help you, it's work with vuetify 2.x.
{
// inside Vue Component
methods: {
openLink(link) {
console.log(`opened link ${link}`)
}
}
}
<v-data-table
:options="{ openLink }"
>
<template v-slot:body="{ items, options }">
<tbody>
<tr
v-for="item in items"
:key="item.id"
>
<td>
<button #click="() => options.openLink(item)" />
</td>
</tr>
</tbody>
</template>
</v-data-table>
Look: Data Table Api - slots.body it is for me, the best approachable to solve this problem.

How to set 'active' for tr/row in v-data-table (Vuetify 2.0+)?

I need to set 'active' for row where is item with property selected: true.
Before i did it with :active="props.item.selected", but now, in new verison of Vuetify it doesnt work.
<v-data-table
hide-default-footer
:items="views.BusinessOperationView.valueList"
:items-per-page="-1"
:headers="views.BusinessOperationView.headers">
<template v-slot:item="props">
<tr
#click="uiBusinessOperationSelectionChange(props.item.businessOperationId)"
:isSelected="props.item.selected"
style="cursor: pointer"
:active = "props.item.selected">
<td><v-card class="pa-2 ma-2 body-1 text-md-center">{{ props.item.loadText }}</v-card></td>
<td>{{ props.item.businessOperationName }}</td>
</tr>
</template>
</v-data-table>
<template v-slot:item="{ item }">
<tr :class="{active: group && item.id == group.id}">
<td>{{ item.name }}</td>
<td>{{ item.grade }}</td>
</tr>
</template>
This is how I do it for data tables with vuetify. The 'active' class could be customized to have a different background color than the default one.

handle promises in Vuetify data tables

I have a problem when trying to insert the response of an API call (I am using axios) into a vue data table. If I manually write an html table like this:
<table style="width:100%">
<tr>
<th v-for="(item, n) in headers" v-bind:key="n">{{item.text}}</th>
</tr>
<tr v-for="(item, n) in info" v-bind:key="n">
<td>{{ item.code }}</td>
<td>{{ item.symbol }}</td>
<td>{{ item.rate }}</td>
<td>{{ item.description }}</td>
<td>{{ item.rate_float }}</td>
</tr>
</table>
the code works and displays some data.
But when I try to use the Vuetify data table like this:
<v-data-table
app
:headers="headers"
:items="info"
class="elevation-2"
>
<template v-slot:items="props">
<td>{{ props.item.code }}</td>
<td>{{ props.item.symbol }}</td>
<td>{{ props.item.rate }}</td>
<td>{{ props.item.description }}</td>
<td>{{ props.item.rate_float }}</td>
</template>
</v-data-table>
it gives me the following warning:
webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:620 [Vue warn]: Invalid prop: type check failed for prop "items". Expected Array, got Object
found in
---> <VDataTable>
<ApiExample> at src/views/ApiExample.vue
<VContent>
<VApp>
<App> at src/App.vue
<Root>
Leading to this error:
webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:1887 TypeError: this.items.map is not a function
at VueComponent.items (webpack-internal:///./node_modules/vuetify/dist/vuetify.js:21511)
at Watcher.run (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:4556)
at flushSchedulerQueue (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:4298)
at Array.eval (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:1979)
at flushCallbacks (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:1905)
The application works if instead of trying to diplay the dynamic data I try to display a statically defined object ("staticitems"). In my opinion the problem is that the data table is expecting an array but instead it finds a Promise so it crashes. Below is the full code for the application .
<template>
<v-container fluid>
<table style="width:100%">
<tr>
<th v-for="(item, n) in headers" v-bind:key="n">{{item.text}}</th>
</tr>
<tr v-for="(item, n) in info" v-bind:key="n">
<td>{{ item.code }}</td>
<td>{{ item.symbol }}</td>
<td>{{ item.rate }}</td>
<td>{{ item.description }}</td>
<td>{{ item.rate_float }}</td>
</tr>
</table>
<v-data-table
app
:headers="headers"
:items="info"
class="elevation-2"
>
<template v-slot:items="props">
<td>{{ props.item.code }}</td>
<td>{{ props.item.symbol }}</td>
<td>{{ props.item.rate }}</td>
<td>{{ props.item.description }}</td>
<td>{{ props.item.rate_float }}</td>
</template>
</v-data-table>
</v-container>
</template>
<script>
import axios from 'axios'
export default {
name: "ApiExample",
data() {
return {
info: [],
info2: [],
headers: [
{text: 'code', value: 'code'},
{text: 'symbol', value: 'symbol'},
{text: 'rate', value: 'rate'},
{text: 'description', value: 'description'},
{text: 'rate_float', value: 'rate_float'},
],
staticitems: [
{
code: "USD",
symbol: "$",
rate: "5,247.0417",
description: "United States Dollar",
rate_float: "5247.0417"
}
]
}
},
mounted() {
axios
.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(response => (this.info = response.data.bpi))
.catch(error => console.error(error))
}
}
</script>
<style scoped>
</style>
type check failed for prop "items". Expected Array, got Object.
It is what it means. Datatable is fine with using data returned from promises as long as the type of response is an array. Your promise is returning an object.
The application works if instead of trying to diplay the dynamic data I try to display a statically defined object ("staticitems").
staticitems is not an object. It is an array of object. Arrays are displayed like this: [] and objects like {}
You need to make sure that the response coming back from an API is an array. I created a simple example from your API call to show you the right format of your response. As you can see info is now an array and the datatable works fine.