0

Have two input in the child components but focusing on the first input which emits the eKey. The second input which specifies the amount is working perfectly.

In the parent component I want the input value of the first input to pushed in the epensesKey array which is set in the data() section.

Note: The bigger picture is for me to send a POST request to my Express Api with the expenseKey and expenseValue array as a key/value pair

Child Component

<template>
  <div class="input">
    <input
      type="text"
      placeholder="Expense"
      @input="$emit('eKey', $event.target.value)"
    />
    <input
      type="number"
      placeholder="Amount"
      @input="$emit('input', { 
        value: $event.target.value,
        id
      })"
    />
  </div>
</template>

<script>
export default {
  name: "formInput",
  props: {
    id: Number,
    eKey: Array
  }
};
</script>

Parent Component

<template>
  <div class="container">

    <h1>Budget Form</h1>

    <div class="form">
      <form action>
        <div class="topForm">
          <label for="monthlypay">Monthly pay</label>
          <input type="number" name="monthlypay" id="monthlypay" v-model="earnings" />
        </div>
      </form>

      <h2>Expenses</h2>
      <form-input v-for="(n,idx) in count" :key="n" :id="idx" :ekey="expensesKey"
      @ekey="ekey = $event" @input="getExpenseValue">
      </form-input>

      <button @click="addInputs">Add Expense</button>
      <button @click="deleteInputs">Delete</button>
      <button type="button" @click="submitBudget">Submt</button>

      <p>Total Monthly Income: {{ earnings }}</p>
      <p>Total Expense: {{ totalExpense }}</p>
      <p>Money left: {{ getDifference }}</p>
    </div>

  </div>
</template>

<script>
import axios from "axios";
import formInput from "../components/Input.vue";

export default {
  components: {
    "form-input": formInput
  },
  name: "form",
  data() {
    return {
      count: 0,
      earnings: "",
      expensesValue: [],
      expensesKey: [],
      totalExpense: ""
    };
  },
  methods: {
    addInputs: function() {
      this.count++;
      this.expensesValue[this.count - 1] = 0;
    },
    deleteInputs: function() {
      this.count--;
      this.expensesValue.pop();

      this.setTotalExpense();
    },
     getExpenseValue(data) {
      this.expensesValue[data.id] = parseInt(data.value, 10) || 0;
      this.setTotalExpense();
    },
    setTotalExpense() {
      console.log(this.expensesValue);

      this.totalExpense = this.expensesValue.reduce((sum, val) => {
        return sum + val;
      }, 0);
    },
    submitBudget() {
      axios
        .post("http://localhost:3000/budget", {
          earning: this.earnings,
          expenses: this.expensesKey
        })
        .then(response => {
          console.log(response.data);
        })
        .catch(e => {
          console.error(e);
        });
    }
  },
  computed: {
    getDifference() {
      return this.earnings - this.totalExpense;
    }
  }
};
</script>

1
  • @T.Short let me know if you need any clarification. Commented Dec 30, 2019 at 11:50

1 Answer 1

1

So in the parent you can do like so:

<template>
  <div class="container">
    <h1>Budget Form</h1>

    <div class="form">
      <form action>
        <div class="topForm">
          <label for="monthlypay">Monthly pay</label>
          <input type="number" name="monthlypay" id="monthlypay" v-model="earnings">
        </div>
      </form>

      <h2>Expenses</h2>
      <form-input
        v-for="(n,idx) in count"
        :key="n"
        :id="idx"
        :e-key="expensesKey"
        @eKey="setExpenseKey"
        @input="getExpenseValue"
      ></form-input>

      <button @click="addInputs">Add Expense</button>
      <button @click="deleteInputs">Delete</button>
      <button type="button" @click="submitBudget">Submt</button>

      <p>Total Monthly Income: {{ earnings }}</p>
      <p>Total Expense: {{ totalExpense }}</p>
      <p>Money left: {{ getDifference }}</p>
    </div>
  </div>
</template>

<script>
import axios from "axios";
import formInput from "./components/Input.vue";

export default {
  components: {
    "form-input": formInput
  },
  name: "form",
  data() {
    return {
      count: 0,
      earnings: "",
      expensesValue: [],
      expensesKey: [],
      totalExpense: ""
    };
  },
  methods: {
    addInputs: function() {
      this.count++;
      this.expensesValue[this.count - 1] = 0;
      this.expensesKey[this.count - 1] = "default";
    },
    deleteInputs: function() {
      if (this.count < 1) {
        return;
      }

      this.count--;
      this.expensesValue.pop();
      this.expensesKey.pop();

      this.setTotalExpense();
    },
    getExpenseValue(data) {
      this.expensesValue[data.id] = parseInt(data.value, 10) || 0;
      this.setTotalExpense();
    },
    setExpenseKey(data) {
      this.expensesKey[data.id] = data.value || "default";
    },
    setTotalExpense() {
      console.log(this.expensesValue);

      this.totalExpense = this.expensesValue.reduce((sum, val) => {
        return sum + val;
      }, 0);
    },
    mergeKeyAndValue() {
      return this.expensesKey.reduce((acc, key, index) => {
        return [...acc, { [key]: this.expensesValue[index] }];
      }, []);
    },
    submitBudget() {
      const expenses = this.mergeKeyAndValue();

      axios
        .post("http://localhost:3000/budget", {
          earning: this.earnings,
          expenses
        })
        .then(response => {
          console.log(response.data);
        })
        .catch(e => {
          console.error(e);
        });
    }
  },
  computed: {
    getDifference() {
      return this.earnings - this.totalExpense;
    }
  }
};
</script>

And in the child, you can do like this:

<template>
  <div class="input">
    <input
      type="text"
      placeholder="Expense"
      @input="$emit('eKey', {
        value: $event.target.value,
        id
      })"
    >
    <input
      type="number"
      placeholder="Amount"
      @input="$emit('input', { 
        value: $event.target.value,
        id
      })"
    >
  </div>
</template>

<script>
export default {
  name: "formInput",
  props: {
    id: Number,
    eKey: Array
  }
};
</script>

Note, I also added a function that will pair the key and values together before posting the data. (I also added some other minor improvements).

You may want to adjust some things to suit your needs.

Let me know if you have any questions.

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

1 Comment

Hey it work! Thanks You! You got some serious skills. I was wondering is there any documentation on the way you use the arrays. For instance in addInput method this.expensesValue[this.count - 1] or getExpenseValue method this.expensesValue[data.id]

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.