Total of Vue Component Subtotals

One of the challenges I'm facing in my Vue app is calculating the total of subtotals.

Every component has its own subtotal that depends on user input. I need to combine these individual subtotals and display the result in an input field outside of the components.

I'm struggling with how to properly reference the component subtotals from outside of the components. Would it be a good approach to add a computed property to the #app for this purpose?

<div id="app">
    <h1 style="padding: 2em 0 1em">Vue.JS Loop 2</h1>
    <div class="total">
        <input :value="form.income" @change="updateIncome" type="number" class="form-control" name="income" id="income" placeholder="Income">
        <!--Add all subtotals here-->
        <input :value="form.expenses" @change="updateExpenses" type="number" step="any" class="form-control" name="expenses" id="expenses" placeholder="Expenses">
        <hr/>
        <input v-model="form.dispIncome" type="number" step="any" class="form-control" name="dispIncome" id="dispIncome" placeholder="Disposable Income">
    </div>
    <div class="budget-container">
        <div class="budget" v-for="budget in budgets">
            {{budget}} Expenses
            <budget-line></budget-line>
        </div>
    </div>
</div>

<script>
    var budgetLine = Vue.extend({
        template: `
            <div>
                <p id="result"><strong>Total:</strong> $ {{ totalQty }} </p>
            <div class="row" v-for="item in items">
                <input type="text" placeholder="Item"></input>
                <input type="text" placeholder="How much?" v-model="item.qty"></input>
                <button @click="addItem">+</button>
                <button @click="removeItem">-</button>
            </div>
            </div>
        `,

        data: function() {
            return { items: [] };
        },

        computed: {
            totalQty() {
                return this.items.reduce((total, item) => {
                    return total + Number(item.qty);
                }, 0);
            },
        },

        methods: {
            addItem() {
                this.items.push({
                    qty: 0
                });
            }, 
            removeItem(item) {
                this.items.pop(item);
            }
        },

        mounted() {
            this.addItem()
        }
    });

    var budgetApp = new Vue({
        el: '#app',
        data: {
            budgets: ['One', 'Two', 'Three'], 
            form: {
                income: 0,
                expenses: 0,
                dispIncome: 0
            }
        }, 
        components: {
            'budget-line': budgetLine
        }, 
        methods: {
            updateIncome(event) {
                this.form.income = event.target.value
                this.form.dispIncome = this.form.income - this.form.expenses
            },
            updateExpenses(event) {
                this.form.expenses = event.target.value
                this.form.dispIncome = this.form.income - this.form.expenses
            }
        }
    });

</script>

Answer №1

Here is the updated code that now displays form expenses as a total of multiple line expenses added under each budget section:

To achieve this, I implemented a combination of watch and computed functions. Here is a summary of the changes made:

  • In the budgetLine component, I added a watcher to emit changes on the totalQty
  • In the budgetApp component, I modified budgets data to an object, added a computed property budgetKeys to render section names, added a calculateExpense method that will be called on emit from budgetLine to update budgets, and added a watcher on budgets to update the form.expenses
var budgetLine = Vue.extend({
  template: `
            <div>
                <p id="result"><strong>Total:</strong> $ {{ totalQty }} </p>
            <div class="row" v-for="item in items">
                <input type="text" placeholder="Item"></input>
                <input type="text" placeholder="How much?" v-model="item.qty"></input>
                <button @click="addItem">+</button>
                <button @click="removeItem">-</button>
            </div>
            </div>
        `,

  data: function() {
    return {
      items: []
    };
  },
  watch: {
    totalQty(value) {
      this.$emit('update-expense', value)
    }
  },
  computed: {
    totalQty() {
      return this.items.reduce((total, item) => {
        return total + Number(item.qty);
      }, 0);
    },
  },

  methods: {
    addItem() {
      this.items.push({
        qty: 0
      });
    },
    removeItem(item) {
      this.items.pop(item);
    }
  },

  mounted() {
    this.addItem()
  }
});

var budgetApp = new Vue({
  el: '#app',
  data: {
    budgets: {
      'One': 0,
      'Two': 0,
      'Three': 0
    },
    form: {
      income: 0,
      expenses: 0,
      dispIncome: 0
    }
  },
  components: {
    'budget-line': budgetLine
  },
  watch: {
    budgets: {
      deep: true,
      handler() {
        this.form.expenses = this.budgetKeys.reduce((accum, key) => accum + this.budgets[key], 0)
      }
    }
  },
  computed: {
    budgetKeys() {
      return Object.keys(this.budgets)
    },
  },
  methods: {
    updateIncome(event) {
      this.form.income = event.target.value
      this.form.dispIncome = this.form.income - this.form.expenses
    },
    updateExpenses(event) {
      this.form.expenses = event.target.value
      this.form.dispIncome = this.form.income - this.form.expenses
    },
    calculateExpense(amount, budget) {
      this.budgets[budget] = amount;
      console.log(this.budgets)
    }
  }
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

jquery events such as onSubmit, onComplete, etc. are commonly used

It's interesting to observe that many tools in jQuery, especially those involving ajax, contain hooks like onSubmit, onComplete, and more. Is there a specific term for this practice and the standards associated with it? Does this practice belong sol ...

Load an XML file from the local server asynchronously on the Chrome web browser

Attempting to load a local XML/XSL file into a variable for editing seems to be causing an issue. The code provided functions properly in IE and Chrome, however, Chrome displays a warning due to the synchronous nature of the call. function loadXMLDoc(fileN ...

Incorporating language modifications using the Laravel Vue Internationalization package

Hey there, I'm exploring Vue and attempting to create a multilingual application. During my research, I came across this package - https://github.com/xiCO2k/laravel-vue-i18n. I successfully installed it and managed to establish the connection for tran ...

Guide on displaying the name attribute of a button along with its price in a separate div when clicked

Upon clicking the Koala button, I want to display a message showing the id name of the button and the corresponding price for Koalas. Here is the HTML code snippet: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <link h ...

Titanium: Warning upon initiation

Is it feasible to trigger an alert immediately after a window finishes loading? I am using a create window function followed by an alert message, then returning. function NewView() { var self = Ti.UI.createWindow({}); alert("A basic or confirm al ...

Issue with Socket.IO: socket.on not executed

Recently, I devised a custom asynchronous emitter for implementing a server -> client -> server method. Regrettably, the functionality is not meeting my expectations. Although it emits the event, it fails to execute the callback as intended. Upon a ...

Click and keystroke fusion

Greetings everyone, I've been attempting to integrate both click and keypress functionalities into my function, but unfortunately, nothing I've attempted so far has yielded any success. Here's the code snippet: function victoryMessage() { ...

Could you explain the distinction between Node.bind() and Template Binding?

Currently, I am exploring the documentation for Google Polymer and have come across two types of data binding - Node.bind() and Template Binding. Can someone please explain the distinction between Node.bind() and Template Binding to me? ...

Switch the header from left to right movement for mobile devices

I am dealing with two headers in my layout <section> <header class="col-lg-9"> <!-- some content --> </header> <header class="col-lg-3"> <!-- some content --> </header> </section ...

Unexpected token { in Fuse-Box when using Typescript

Here's the beginning of my fuse.ts file import { CSSPluginOptions } from 'fuse-box/plugins/stylesheet/CSSplugin'; import { argv } from 'yargs'; import * as path from 'path'; import { CSSPlugin, CSSResourcePlugin, Env ...

manipulating elements of an array within a .map method

i am stuck with a json exporting database. it generates json data in the following format. {"Drinks":[ { "name":"name", "discription":"discription", "image":"image", "ingredients&qu ...

Node.js: How to handle spaces when running a UNIX command

Currently, I am utilizing the following command to compress files in node.js: var command = '7z a ' + dest + ' ' + orig; exec( command, function(err, stdout, stderr) { ...}); An issue arises when a file containing spaces is involved, ...

Transferring an array from PHP to JavaScript via an Ajax response

Welcome to my first post on stackoverflow. I usually find answers from existing posts, but this time I'm facing a problem that none of the suggested solutions have been able to fix. Currently, I have a JavaScript function that makes an AJAX request t ...

Can I use Javascript to make changes to data stored in my SQL database?

I am delving into the realm of SQL and Javascript, aiming to insert my variable ("Val_Points from javascript") into a table ("Usuarios") associated with a specific user (e.g., Robert). Is it possible to achieve this using JavaScript, or are there alternati ...

Determine the cost for every individual line

I need help figuring out how to calculate the price for each row. Whenever I choose a quantity, it's showing the same price for both rows. Check out my demo here: https://jsfiddle.net/keyro/fw8t3ehs/2/ Thank you in advance! HTML: <table class=" ...

Issue: Reactjs - Material-UI HTML Tooltip does not display dynamic HTML content.In the Reactjs

I have been using a customized HTML MUI Tooltip. Currently, it is functioning with static content but I am looking to make it dynamic. Unfortunately, it is not working with dynamic HTML content. Here is my attempted approach: const ADJUSTMENT_HELP_TEXT = ...

Building a Dynamic Checkbox Validation Feature in Angular Using Data retrieved from an API

Currently, I have a function that retrieves and displays a list obtained from an API: displayEventTicketDetails() { this.Service .getEventTicketDetails().subscribe((data: any) => { this.eventTicketDetails = data.map(ticket => ticket. ...

Creating Bubble Charts using npm highcharts with error code #17

I am attempting to create a bubble chart using Highcharts with the npm version, but I keep encountering error #17. I have tried importing highcharts-more without success... Here are my imports: import $ from "jquery"; import _ from "underscore"; import L ...

Exploring the capabilities of arrays within Ajax

Below is the original code I wrote in JavaScript: var wt_val = []; for (i = 0; i<human_wt.length; i++){ var mult; mult = data_list[basket_list[button_port_name][i]].map(x => x*(wt[i]/100)); wt_val.push(mult); ...

Display a div with a link button when hovering over an image

Currently, I'm attempting to display a link button within a div that will redirect the user to a specified link upon clicking. Unfortunately, my current implementation is not functioning as expected. I have provided the code below for reference - plea ...