I have a form composed of 1 or more (user decides) Transactions. I display Transactions inside a component on the parent and set the Transaction's attributes with computed properties in the child (Transaction) component.
User data is updated by the computed properties just fine however, when a user clicks to add an additional Transaction component the values from the first Transaction are duplicated for any new Transaction component/object created.
I have read in the forum here and here that the solution was to use a function for state in the module definition. This doesn't appear to work for me, I'd like to learn why.
Here is the declaration of the composite component Transaction:
<template v-for="(fund_transaction, index) in fund_transactions">
<div class="card">
<div class="card-body">
<FundTransactionComponent
v-bind:fund_transactions="fund_transactions"
v-bind:key="index"
v-on:removedTransaction="removeFundTransaction(id)"
v-on:submittedTransaction="applyFundTransaction(fund_transaction.id)"
>
</FundTransactionComponent>
</div><!--END .card-body-->
</div><!--END .card-->
</template>
And here is the child component (computed props truncated for brevity, they are just the state attributes both getters and setters):
<template>
<div class="row">
<div class="col-10 float-left" v-if="this.fund_transactions.length > 0"></div>
<div class="col-2 float-right" v-if="this.fund_transactions.length > 0">
<button v-on:click="removeTransaction(index)" class="btn btn-icon btn-danger px-2 py-1 float-right">
<i class="fa fa-times"></i>
</button>
</div><!--END .col-1 float-right-->
<div class="col-md-6 col-sm-12">
<label class="form-control-label text-semibold">Transaction Date:</label>
<el-date-picker
type="date"
placeholder="select a date"
v-model="date_of_record"
style="width: 100%;"
format="MMMM dd, yyyy"
clearable
default-date="Date.now()"
>
</el-date-picker>
</div><!--END .col-md-6 .col-sm-12-->
<div class="col-md-6 col-sm-12">
<label class="form-control-label text-semibold">Reason for Transaction:</label>
<textarea class="form-control" placeholder="Enter reason here.." v-model="reason_for_transaction">
</textarea>
</div><!--END .col-md-6 .col-sm-12-->
<div class="col-md-6 col-sm-12">
<label class="form-control-label text-semibold">Transaction Amount:</label>
<input type="text" class="form-control" v-model="amount"/>
</div><!--END .col-md-6 .col-sm-12-->
<div class="col-md-6 col-sm-12">
<label class="form-control-label text-semibold">Type of Transaction:</label><br>
<el-radio-group
v-model="transaction_type">
<el-radio-button label="Deposit"></el-radio-button>
<el-radio-button label="Withdrawal"></el-radio-button>
</el-radio-group>
</div><!--END .col-md-6 .col-sm-12-->
<div class="col-md-6 col-sm-12">
<label class="form-control-label text-semibold">Current Balance:</label>
<input type="text" class="form-control" v-model="current_balance"/>
</div><!--END .col-md-6 .col-sm-12-->
<div class="col-md-6 col-sm-12">
<label class="form-control-label text-semibold">Forwarded:</label>
<input type="text" class="form-control" v-model="forwarded"/>
</div><!--END .col-md-6 .col-sm-12-->
</div><!--END .row-->
</template>
<script>
import moment from "moment";
import DatePicker from 'vuejs-datepicker';
import FundRecordForm2 from "@/store/modules/forms/FundRecordForm2";
import FundTransaction from "@/store/modules/auxillary/FundTransaction";
import Resident from "@/store/modules/actors/Resident";
export default {
name: "FundTransaction",
components: {
DatePicker,
},
props: {
index: {
type: Number,
required: false,
},
},
computed: {
id: {
get() {
return this.$store.getters['FundTransaction/getId'];
},
set(value) {
this.$store.dispatch('FundTransaction/setId', value);
},
},
},
.
.
.
};
</script>
<style scoped>
</style>
Here is the vuex module for the child component (Transaction):
import Axios from "axios";
import router from "../../../router";
import FundRecordForm2 from "../forms/FundRecordForm2";
const FundTransaction = {
namespaced: true,
// Expectation: this should return individual object state respsectively
// state: () => ({})
state () {
return {
id: null,
provider_id: Number,
employee_id: Number,
account_id: Number,
resident_id: Number,
fund_record_form2_id: Number,
transaction_date: '',
reason_for_transaction: '',
transaction_type: '',
amount: 0.0,
current_balance: 0.0,
forwarded: 0.0,
date_of_record: '',
created_at: '',
updated_at: '',
}
},
getters: {
getId: (state) => {
return state.id;
},
getProviderId: (state) => {
return state.provider_id;
},
getEmployeeId: (state) => {
return state.employee_id;
},
getAccountId: (state) => {
return state.account_id;
},
getResidentId: (state) => {
return state.resident_id;
},
getFundRecordForm2Id: (state) => {
return state.fund_record_form2_id;
},
getTransactionDate: (state) => {
return state.transaction_date;
},
getReasonForTransaction: (state) => {
return state.reason_for_transaction;
},
getTransactionType: (state) => {
return state.transaction_type;
},
getAmount: (state) => {
return state.amount;
},
getCurrentBalance: (state) => {
return state.current_balance;
},
getForwarded: (state) => {
return state.forwarded;
},
getDateOfRecord: (state) => {
return state.date_of_record;
},
getCreatedAt: (state) => {
return state.created_at;
},
getUpdatedAt: (state) => {
return state.updated_at;
},
getFundTransaction: (state) => {
return state.fund_transaction;
},
},
mutations: {
SET_ID: (state, payload) => {
state.id = payload;
},
SET_PROVIDER_ID: (state, payload) => {
state.provider_id = payload;
},
SET_EMPLOYEE_ID: (state, payload) => {
state.employee_id = payload;
},
SET_ACCOUNT_ID: (state, payload) => {
state.account_id = payload;
},
SET_RESIDENT_ID: (state, payload) => {
state.resident_id = payload;
},
SET_FUND_RECORD_FORM2_ID: (state, payload) => {
state.fund_record_form2_id = payload;
},
SET_TRANSACTION_DATE: (state, payload) => {
state.transaction_date = payload;
},
SET_REASON_FOR_TRANSACTION: (state, payload) => {
state.reason_for_transaction = payload;
},
SET_TRANSACTION_TYPE: (state, payload) => {
state.transaction_type = payload;
},
SET_AMOUNT: (state, payload) => {
state.amount = payload;
},
SET_CURRENT_BALANCE: (state, payload) => {
state.current_balance = payload;
},
SET_FORWARDED: (state, payload) => {
state.forwarded = payload;
},
SET_DATE_OF_RECORD: (state, payload) => {
state.date_of_record = payload;
},
SET_CREATED_AT: (state, payload) => {
state.created_at = payload;
},
SET_UPDATED_AT: (state, payload) => {
state.updated_at = payload;
},
UPDATE_FUND_TRANSACTION: (state, pyaload) => {
state.fund_transaction = payload;
},
},
actions: {
setId (context, payload) {
context.commit('SET_ID', payload);
},
setProviderId (context, payload) {
context.commit('SET_PROVIDER_ID', payload);
},
setEmployeeId (context, payload) {
context.commit('SET_EMPLOYEE_ID', payload);
},
setAccountId (context, payload) {
context.commit('SET_ACCOUNT_ID', payload);
},
setResidentId (context, payload) {
context.commit('SET_RESIDENT_ID', payload);
},
setFundRecordForm2Id (context, payload) {
context.commit('SET_FUND_RECORD_FORM2_ID', payload);
},
setTransactionDate (context, payload) {
context.commit('SET_TRANSACTION_DATE', payload);
},
setReasonForTransaction (context, payload) {
context.commit('SET_REASON_FOR_TRANSACTION', payload);
},
setTransactionType (context, payload) {
context.commit('SET_TRANSACTION_TYPE', payload);
},
setAmount (context, payload) {
context.commit('SET_AMOUNT', payload);
},
setCurrentBalance (context, payload) {
context.commit('SET_CURRENT_BALANCE', payload);
},
setForwarded (context, payload) {
context.commit('SET_FORWARDED', payload);
},
setDateOfRecord (context, payload) {
context.commit('SET_DATE_OF_RECORD', payload);
},
setCreatedAt (context, payload) {
context.commit('SET_CREATED_AT', payload);
},
setUpdatedAt (context, payload) {
context.commit('SET_UPDATED_AT', payload);
},
updateFundTransaction (context, payload) {
context.commit('UPDATE_FUND_TRANSACTION', payload);
},
},
}
export default FundTransaction;
Update:
I pass an object literal like so..
SET_NEW_FUND_TRANSACTION_FIELDS: (state) => {
state.fund_transactions.push({
id: null,
provider_id: Number,
employee_id: Number,
account_id: Number,
resident_id: Number,
fund_record_form2_id: Number,
transaction_date: '',
reason_for_transaction: '',
transaction_type: '',
amount: 0.0,
current_balance: 0.0,
forwarded: 0.0,
date_of_record: '',
created_at: '',
updated_at: '',
});
},
I also tried wrapping my state in Transaction namespace, setting up a getter for this object and using it in the parent.
SET_NEW_FUND_TRANSACTION_FIELDS: (state, getters, rootState, rootGetters) => {
state.fund_transactions.push(rootGetters['FundTransaction/getFundTransaction']);
},
FundTransaction's state:
state: () => ({
fund_transaction: {
id: null,
provider_id: Number,
employee_id: Number,
account_id: Number,
resident_id: Number,
fund_record_form2_id: Number,
transaction_date: '',
reason_for_transaction: '',
transaction_type: '',
amount: 0.0,
current_balance: 0.0,
forwarded: 0.0,
date_of_record: '',
created_at: '',
updated_at: '',
}
}),
getFundTransaction: (state) => {
return state.fund_transaction;
},
But this returns the duplicates as before.
Looking forward to your recommendation.
fund_transactions
, what is its empty state in the parent? I suspect you need to handle that differently. – Calkstate.fund_transactions.push(rootGetters['FundTransaction/getFundTransaction']);
it looks like you only have one FundTransaction instead of a module for each FundTransaction. In that case you might have something likerootGetters['FundTransaction-7/getFundTransaction']
. – Usanis