2

I have the following template and I want to call a method of the dynamically created components in the v-for statement.

For example I want to call on each row the row.getSubtotal() method. I do not know how to do it as this.rows returns the original array and not the array of components.

 <template>
    <div>
        <table class="table table-bordered">
            <thead>
                <th  v-for="c in columns" v-bind:class="[c.className ? c.className : '']" :key="c.code">{{c.label}}</th>
            </thead>
            <tbody>
            <row v-for="(row, index) in rows"
                 :index="index+1"
                 :init-data="row"
                 :columns="columns"
                 :key="row.hash"
                 :hash="row.hash"
                 v-on:remove="removeRow(index)"></row>
            </tbody>
        </table>
        <div class="d-flex">
            <table>
                <tr>
                    <td>Unique SKUs:</td>
                    <td>{{rows.length}}</td>
                    <td>Total units:</td>
                    <td>{{totalUnits}}</td>
                </tr>
            </table>
            <span class="flex-fill"></span>
            <button class="btn" @click="newRow">Nueva línea</button>
        </div>
    </div>
</template>

The <row> element is a Vue component that it's created via the rows property that contains an array of objects with each rows property. For example:

...
import Row from './Row'

export default {
    name: "OrderTable",
    components: {Row},
    data: () => ({
        hashes: [],
        rows: [
           {hash: '_yug7', sku: '85945', name: 'Coconut butter', price: 20},
           {hash: '_g484h', sku: '85745', name: 'Coconut oil', price: 15},
           {hash: '_yug7', sku: '85945', name: 'Cramberry juice', price: 5},
        ],
        fixedColumns: [
            {code: 'index', label: '#'},
            {code: 'sku', label: 'SKU'},
            {code: 'name', label: 'Product name', className: 'text-left align-middle'},
            {code: 'quantity', label: 'Units'},
            {code: 'price', label: 'Price', className: 'text-right align-middle'}
        ]
    }),
    computed: {
        totalUnits: function () {
            for(let x in this.rows) {
                // HERE I WANT TO CALL A METHOD IN THE ROW COMPONENT
                // For example this.rows[x].getSubtotal()
            }
        }
    },
...

2 Answers 2

5

Dynamically create a ref attribute on each component and call it afterwards:

<template>
    <div>
        <table class="table table-bordered">
            <thead>
                <th  v-for="c in columns" v-bind:class="[c.className ? c.className : '']" :key="c.code">{{c.label}}</th>
            </thead>
            <tbody>
            
            <!-- Add the ref attribute to each row -->
            <row v-for="(row, index) in rows"
                 :ref="`myRow${index}`"
                 :index="index+1"
                 :init-data="row"
                 :columns="columns"
                 :key="row.hash"
                 :hash="row.hash"
                 v-on:remove="removeRow(index)"></row>

            </tbody>
        </table>
        <div class="d-flex">
            <table>
                <tr>
                    <td>Unique SKUs:</td>
                    <td>{{rows.length}}</td>
                    <td>Total units:</td>
                    <td>{{totalUnits}}</td>
                </tr>
            </table>
            <span class="flex-fill"></span>
            <button class="btn" @click="newRow">Nueva línea</button>
        </div>
    </div>
</template>

To call a method on the component, do this:

computed: {
        totalUnits: function () {
            for(let (x, index) in this.rows) {
                let row = this.$refs[`myRow${index}`]
                // You now have an instance of the component
                let subtotal = row.getSubtotal()
            }
        }
    },

More information for the $refs attribute here: what's the real purpose of 'ref' attribute?

Sign up to request clarification or add additional context in comments.

Comments

0

Consider v-for and v-model combination to export all the data you need from your row children. Your <row /> will need to implement the v-model interface so look it up.

Of course you could use actions $emit(),$on(), etc. and make rows signal the parent component their states everytime they need to.

Hope this points you to the right direction.

2 Comments

Thanks for your answer, but no, it's not solving my problem. Even if I listen to an event emitted by the children I would get the data (quantity, discount, price...) of that item alone and not all the items in the table/cart. I need to SUM all the quantities and all the subtotals
Every child will emit its own state, yes. But the parent has to store them in some kind of collection (array). Then you will be able to process this collection using Array.map(), Array.reduce() etc. to get your totals.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.