Reputation: 5996
I'm learning vuejs and am implementing a report system, taking some data from a mock API and outputting it into a table. The data returns monthly order numbers and values for multiple years. An example of the data is here: https://api.myjson.com/bins/u5gp6.
What I want to do is loop through each year and month and output the number of orders and order values, with a sum per year.
The HTML is like this:
<div id="app">
<div v-for="report in reports">
<h2>{{ report.year }}</h2>
<table class="table table-striped">
<thead>
<tr>
<th>Month</th>
<th>Number of orders</th>
<th>Total revenue</th>
<th>Average order</th>
</tr>
</thead>
<tbody>
<tr v-for="value in report.values">
<td>{{ value.month }} {{ value.year }}</td>
<td>{{ value.orders }}</td>
<td>£{{ value.revenue }}</td>
<td>£{{ value.average }}</td>
</tr>
</tbody>
<tfoot v-if="reports">
<tr>
<td>Total {{report.year }}</td>
<td>{{ totalOrders }}</td>
<td>£{{ totalRevenue }}</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</div>
The JS is like this:
const app = new Vue({
el: '#app',
data: {
reports: []
},
created() {
fetch('https://api.myjson.com/bins/u5gp6')
.then(response => response.json())
.then(json => {
this.reports = json.reports
});
},
computed: {
totalOrders: function () {
},
totalRevenue: function () {
}
}
});
A fiddle can be seen here: https://jsfiddle.net/eywraw8t/63295/
The part I'm struggling with is calculating the totalOrders
and totalRevenue
values for each year.
I've tried various things like adding a reduce
function in the computed total functions but just can't get anything to work. I think I'm getting confused by the fact this is a nested loop.
Can anyone suggest how to approach this such that totalOrders
and totalRevenue
are populated correctly?
Many thanks.
Upvotes: 2
Views: 4760
Reputation: 721
You can try this.
var array = [
{name: "Peter", age: 43},
{name: "John", age: 32},
{name: "Jake", age: 21}
];
array.reduce(function(sum, current) {
return sum + current.age;
}, 0); // 43 + 32 + 21 = 96
Upvotes: 0
Reputation: 5996
I found that using methods
and passing the values
object of the current year in the loop through as a parameter, I was able to call the reduce method just on the orders and revenues in that particular year, without having to loop through everything each time. The resultant working code is…
HTML:
<div id="app">
<div v-for="report in reports">
<h2>{{ report.year }}</h2>
<table class="table table-striped">
<thead>
<tr>
<th>Month</th>
<th>Number of orders</th>
<th>Total revenue</th>
<th>Average order</th>
</tr>
</thead>
<tbody>
<tr v-for="value in report.values">
<td>{{ value.month }} {{ value.year }}</td>
<td>{{ value.orders }}</td>
<td>£{{ value.revenue }}</td>
<td>£{{ value.average }}</td>
</tr>
</tbody>
<tfoot v-if="reports">
<tr>
<td>Total {{report.year }}</td>
<td>{{ totalOrders(report.values) }}</td>
<td>£{{ totalRevenue(report.values) }}</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</div>
JS:
const app = new Vue({
el: '#app',
data: {
reports: []
},
created() {
fetch('https://api.myjson.com/bins/16731e')
.then(response => response.json())
.then(json => {
this.reports = json.reports
});
},
methods: {
totalOrders: function (values) {
return values.reduce((acc, val) => {
return acc + parseInt(val.orders);
}, 0);
},
totalRevenue: function (values) {
return values.reduce((acc, val) => {
return acc + parseInt(val.revenue);
}, 0);
}
}
});
Working fiddle: https://jsfiddle.net/4js8L3p9/.
Upvotes: 2
Reputation: 92461
You can get a report of sales and orders broken out by year with reduce
on the original array and then calling reduce
on each year's values
.
For example:
let reports = [{"year":"2018","values":[{"month":"Jan","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Feb","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Mar","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Apr","orders":"5","revenue":"50.00","average":"10.00"},{"month":"May","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Jun","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Jul","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Aug","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Sep","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Oct","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Nov","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Dec","orders":"5","revenue":"50.00","average":"10.00"}]},{"year":"2017","values":[{"month":"Jan","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Feb","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Mar","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Apr","orders":"5","revenue":"50.00","average":"10.00"},{"month":"May","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Jun","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Jul","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Aug","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Sep","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Oct","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Nov","orders":"5","revenue":"50.00","average":"10.00"},{"month":"Dec","orders":"5","revenue":"50.00","average":"10.00"}]}]
function totalRevenue(){
return reports.reduce((obj, year) => {
obj[year.year] = year.values.reduce((total, month) => {
return total + parseInt(month.revenue)
}, 0)
return obj
}, {})
}
console.log(totalRevenue())
You can do the same thing with orders by replacing month.revenue
with month.orders
. You could also let the functions take a year
argument and then just report that year, but it probably makes sense to only loop through once if you will be reporting every year on the page.
Upvotes: 1