hawk
hawk

Reputation: 71

VueJs: computed properties inside an iterated property

I am not sure if the question title is the best way to accomplish what I am trying to do but first let me explain the problem:

I have a Vue root component with a property defined in the data key, for example months. In the DOM I iterate over the property using v-for="month in months". Each of these month objects has a list of orders and for each order in orders one line is displayed in a row, with information such as order.date and order.total. This all works fine.

Now I want the bottom row to show an accumulated total for each month, but this is not available as a pre calculated property so my first guess would be to use calculated properties. But how do I define calculated properties that don't depend on the root component but on each child of an iterated property?

Another solution could possibly be using components, but I don't want to define the template inside the component but rather use what is defined in the HTML. I have not yet found a way to do this. Would this be possible? Are there any other possible solutions that I have overlooked?

Upvotes: 0

Views: 113

Answers (3)

Jorge Urosa
Jorge Urosa

Reputation: 11

I´ve solved it as you wanted in the comuted property. check it if you find something interesting.

<template>
<div class="container">
    <div class="row">
        <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
            <div v-for="(month,index) in months" :key="index">
                <p>{{ month.name }}</p>
                <ul>
                    <li v-for="(order,index) in month.orders" :key="index">
                        {{ order.title}} Total :{{ order.total}}
                    </li>
                </ul>
                Total for {{ month.name}}: {{ totalMonth[index]}}
                <hr>

            </div>
        </div>
    </div>
</div>

<script>
export default {
    data () {
        return {
            months:[
                {   name: 'January',
                    orders: [
                        {title: 'order1', total: 5},
                        {title: 'order2', total: 8},
                        {title: 'order3', total: 1}
                        ]
                },
                {   name: 'February',
                    orders: [
                    {title: 'order4', total: 15},
                    {title: 'order5', total: 3}
                    ]
                },
                {   name: 'March',
                    orders: [
                    {title: 'order6', total: 25}
                    ]
                }
            ]
        }
    },
    computed: {
        totalMonth () {
            return this.months.map(a => a.orders.map(a => a.total).reduce((a,b) => a + b))
        }
    }
}

Upvotes: 1

hawk
hawk

Reputation: 71

As it often happens, I found a solution shortly after formulating this question. What I am doing now is:

Defining a property in the root component as follows:

total: function (month) {
    // calculate total
},

In the DOM I display it using {{ total(month) }} €

This may not be an ideal solution but it works for now. If anyone has a better solution I would still appreciate the input, as I am still new to vue.js

Upvotes: 0

M&#225;t&#233; Wiszt
M&#225;t&#233; Wiszt

Reputation: 410

I think the best way would be to create a component for every month (and every order if it is really needed). If you want to avoid this, you can say in the month markup (assumed that orders is an array of numbers):

<p class="orders_total">{{month.orders.reduce((acc, el, i, arr) => acc + el )}}</p>

It is not a good practice because we should not define such array transformation in the markup but it should work.

Upvotes: 1

Related Questions