vue.js render table with rowspans - javascript

I'm new to vue.js and I couldn't find a way to render the following data into an html table with rowspans using vue.
{
"title":"Monthly Sales",
"monthlySales":[
{
"product":"P123",
"months":[
{
"month":"January",
"unitPrice":"$80",
"unitsSold":2200
},
{
"month":"February",
"unitPrice":"$82",
"unitsSold":1900
},
{
"month":"March",
"unitPrice":"$81",
"unitsSold":1800
}
]
},
{
"product":"Q456",
"months":[
{
"month":"January",
"unitPrice":"$20",
"unitsSold":200
},
{
"month":"February",
"unitPrice":"$22",
"unitsSold":100
}
]
}
]
}
I wanted to create an output like this: http://jsbin.com/hucufezayu/edit?html,output
How can we render this kind of table with this data?

This should do the trick:
<template>
<div id="app">
<table border="1" style="border-collapse: collapse">
<thead>
<th>Product</th>
<th>Month</th>
<th>Unit price</th>
<th>No. sold</th>
</thead>
<tbody>
<template v-for="mSale in salesData.monthlySales">
<tr v-for="(month, key) in mSale.months">
<td v-if="key == 0" :rowspan="mSale.months.length"> {{mSale.product}}</td>
<td>{{month.month}}</td>
<td>{{month.unitPrice}}</td>
<td>{{month.unitsSold}}</td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
salesData: jsonData
}
}
}
</script>

Related

Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'path' in undefined

I am a new learner. I am trying to add cart feature using vue. Here is my view name Cart.vue for the cart.
<template>
<div class="page-cart">
<div class="columns is-multiline">
<div class="column is-12">
<h1 class="title">Cart</h1>
</div>
<div class="column is-12 box">
<table class="table is-fullwidth" v-if="cartTotalLength">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
<th></th>
</tr>
</thead>
<tbody>
<CartItem
v-for="item in cart.items"
v-bind:key="item.product.id"
v-bind:initialItem="item" />
</tbody>
</table>
<p v-else>You don't have any products in your cart...</p>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import CartItem from '#/components/CartItem.vue'
export default {
name: 'Cart',
components: {
CartItem
},
data() {
return {
cart: {
items: []
}
}
},
mounted() {
this.cart = this.$store.state.cart
},
computed: {
cartTotalLength() {
return this.cart.items.reduce((acc, curVal) => {
return acc += curVal.quantity
}, 0)
},
}
}
</script>
This is the CartItem.vue component that I used:
<template>
<tr>
<td><router-link :to="item.product.get_absolute_url">{{ item.product.name }}</router-link></td>
<td>Rs {{ item.product.price }}</td>
<td>
{{ item.quantity }}
</td>
<td>Rs {{ getItemTotal(item).toFixed(2) }}</td>
<td><button class="delete"></button></td>
</tr>
</template>
<script>
export default {
name: 'CartItem',
props: {
initialItem: Object
},
data() {
return {
item: this.initialItem
}
},
methods: {
getItemTotal(item) {
return item.quantity * item.product.price
}
},
}
</script>
I cannot see any product and the related values in the cart. I am getting this error -
Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'path' in undefined.
I am unable to find out the mistake in my code. Please help me out. When I am removing the component from the cart.vue, then the error gets eliminated. But I need that component.

How can I make Vue Sortable work on table?

I have an issue with this library. First of all, to test the library, I made a simple example work with ul and li tags. It was straightforward. Then, I needed to do a table, and when converting my example to a table it didn't work.
Table is showed but I cannot move any row.
I'm using the cdn way.
I think is something what I missing.
html
<div id='app-example-drag' >
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th scope="col">Id</th>
<th scope="col">Name</th>
<th scope="col">Sport</th>
</tr>
</thead>
<draggable v-model="list" tag="tbody">
<tr v-for="item in list" :key="item.name">
<td scope="row">{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.sport }}</td>
</tr>
</draggable>
</table>
</div>
js
Vue.component('draggable',vuedraggable);
applicationExample = new Vue({
el: '#app-example-drag',
display: "Table",
order: 8,
data() {
return {
list: [
{ id: 1, name: "Abby", sport: "basket" },
{ id: 2, name: "Brooke", sport: "foot" },
{ id: 3, name: "Courtenay", sport: "volley" },
{ id: 4, name: "David", sport: "rugby" }
]
};
}
});
https://jsfiddle.net/0Luhd694/3/
Thanks in advance
I just ran into this same problem. I think it has something to with recent version. Replace the draggable element with a tbody and make is='draggable'.
<div id='app-example-drag' >
<table class='table'>
<thead>
<tr><th scope='col'>description</th></tr>
</thead>
<tbody tag='tbody' v-model='lista1' is='draggable' group='items'>
<tr v-for='item in lista1' :key='item.id'>
<td scope='row'>{{item.description}}</td>
</tr>
</tbody>
</table>
</div>
https://jsfiddle.net/oqf64kdx/

How to share data between two component in vuejs with Event Bus

I am trying to implement a global event bus in order to send a variable from component A to component B.
Here is the component A code:
data () {
return {
commandes: [],
}
},
envoyer() {
this.$eventBus.$emit('commande', this.commandes);
},
Here is the component B code:
<template>
<div class="container">
<div class="row justify-content-center">
<!-- Table row -->
<div class="row">
<div class="col-12 table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Qté</th>
<th>Produit</th>
<th>Subtotal</th>
</tr>
</thead>
<tbody>
<tr v-for="(commande, index) in commandes" :key="index">
<td>{{ commande.quantite }}</td>
<td>{{ commande.produit_id }}</td>
<td>{{ commande.montant }}</td>
</tr>
</tbody>
</table>
</div>
<!-- /.col -->
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
commande: [],
}
},
methods: {
},
mounted() {
this.$eventBus.$on('commande', (commandes) => {
this.commande = commandes;
console.log(commandes);
})
}
}
</script>
I'm getting this error when component B is displayed:
[Vue warn]: Property or method "commandes" is not defined on the instance but referenced during render.
How to solve this?
In your template you are referencing commandes
<tr v-for="(commande, index) in commandes" :key="index">
but your data doesn't return it, it returns commande
data() {
return {
commande: [],
}
}
Update your data and bus listeners:
data() {
return {
commandes: [],
}
}
...
this.$eventBus.$on('commande', (commandes) => {
this.commandes = commandes;
console.log(commandes);
})

How to put content under certain headings

How to put content under certain headings?
I have two methods to load data
first axios.get('/api/get/headers')
second axios.get('api/get/contents')
I have no idea how correctly this will be done, given that the headers can be different and the content is correspondingly too
table example
<thead>
<tr>
<th v-for="header in headers" :data-key="header.name">{{ header.title }}</th>
</tr>
</thead>
<tbody>
<tr v-for="content in contents">
<td :data-key="content.name"> {{content.title}}</td>
</tr>
</tbody>
The global problem is that the content can be an array
Here's a one-page example of a way to use axios with Vue.js to get some simple content on the page. Does this help you get started?
<html>
<head>
<script src="http://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<div class="header">{{headerText}}</div>
<div class="content">{{contentText}}</div>
</div>
</body>
<script>
var vm = new Vue({
el: "#app",
data: function () {
return {
headerText: '',
contentText: ''
}
},
mounted: function () {
axios.get("/api/get/headers").then(response => {
this.headerText = response;
})
.catch(err => {
console.log(err);
});
axios.get("/api/get/content").then(response => {
this.contentText = response;
})
.catch(err => {
console.log(err);
});
}
});
</script>
</html>
Update:
For your specific example, could you go through the list of headers again and match the name property with the content name property, and then display the content? Like so:
<thead>
<tr>
<th v-for="header in headers" :data-key="header.name">{{ header.title }}</th>
</tr>
</thead>
<tbody>
<tr v-for="header in headers">
<td :data-key="header.name"> {{getContent(header.name).title}}</td>
</tr>
</tbody>
<script>
...
methods: {
getContent(name) {
for (var index in this.contents) {
if (this.contents[index].name === name) {
return this.contents[index];
}
}
}
}
...
</script>

Vue.js 2 components parent child item not defined

I am new to vue and I am getting the error referenceError: items is not defined. Can anyone see why this happens or give me some pointers?
I think it has something to do with the items not being set on first look at the template.
My code:
<div id="root">
<task-list></task-list>
<template id="my-parent">
<table>
<thead>
<tr>
<th>Name</th>
<th>id</th>
</tr>
</thead>
<tbody>
<tr is="task" v-for="item in items" :item="item"></tr>
</tbody>
</table>
</template>
<template id="my-child">
<tr>
<td></td>
<td>{{ item.name }}</td>
<td>{{ item.id }}</td>
</tr>
</template>
</div>
<script>
Vue.component('task-list', {
template: '#my-parent',
data: function() {
return {
items: []
}
},
methods: {
getMyData: function(val) {
var _this = this;
$.ajax({
url: 'vuejson.php',
method: 'GET',
success: function (data) {
console.log(data);
_this.items = data;
},
error: function (error) {
alert(JSON.stringify(error));
}
})
}
},
mounted: function () {
this.getMyData("0");
}
});
Vue.component('task', {
template: '#my-child',
props: ['item'],
data: function() {
return {
item: {}
}
}
});
new Vue({
el: "#root",
});
</script>
Here is working modified code:
<template id="my-child">
<tr>
<td>{{ item.name }}</td>
<td>{{ item.id }}</td>
</tr>
</template>
<template id="my-parent">
<table>
<thead>
<tr>
<th>Name</th>
<th>id</th>
</tr>
</thead>
<tbody>
<tr is="task" v-for="item in items" :item="item"></tr>
</tbody>
</table>
</template>
<div id="root">
<task-list></task-list>
</div>
And js:
Vue.component('task-list', {
template: '#my-parent',
data: function() {
return {
items: []
}
},
methods: {
getMyData: function(val) {
var _this = this;
_this.items = [{name: '1.name', id: 1}];
}
},
mounted: function () {
this.getMyData("0");
}
});
Vue.component('task', {
template: '#my-child',
props: ['item'],
data: function() {
return {
}
}
});
new Vue({
el: "#root",
});
jsfiddle
It would be much easier to you to work with vue, if you do some tutorials first:)
edit:
And one more thing: if you declare property(item in your case), dont use that name in data.
So, what I did:
- placed templates outside of your root element
- removed "item" from data
You should describe templates outside div#root.
Example
<div id="root">
<task-list></task-list>
</div>
<template id="my-parent">
<table>
<thead>
<tr>
<th>Name</th>
<th>id</th>
</tr>
</thead>
<tbody>
<tr is="task" v-for="item in items" :item="item"></tr>
</tbody>
</table>
</template>
<template id="my-child">
<tr>
<td></td>
<td>{{ item.name }}</td>
<td>{{ item.id }}</td>
</tr>
</template>
Because if they are in #root they are part of vue instance for it, and there is no items in it.
new Vue({
el: "#root",
//no items
});

Categories