0👍
✅
Welcome to Stack Overflow. I’ve made an attempt at fixing your code, tbh I found it really difficult to understand and I think you’re overusing computed properties, e.g.
items: function() {
return this.obj
},
You might as well just reference this.obj instead of this.items as you’re over complicating your code.
Your main problem was initialising the data, Since Vue doesn’t allow dynamically adding root-level reactive properties, you have to initialize Vue instances by declaring all root-level reactive data properties upfront, even with an empty value
Declaring Reactive Properties
So I initialised s
like this:
let s = [{
subitems: [{
eprice: "0",
factor: 0,
discount: 0,
qty: 0,
dprice: 0,
tp1: 0,
margin: 0,
tp2: 0
}]
}];
let s = [{
subitems: [{
eprice: "0",
factor: 0,
discount: 0,
qty: 0,
dprice: 0,
tp1: 0,
margin: 0,
tp2: 0
}]
}];
Vue.component('subitem-row', {
props: ['subitem', 'crt', 'si'],
template: `
<tr>
<td>
<div class="form-group" v-if="crt == si">
<label>EPE</label>
<input v-model="subitem.eprice" @change="calculateSubitem();">
</div>
<span v-else>{{subitem.eprice}}</span>
</td>
<td>
<div class="form-group" v-if="crt == si" @change="parseExpresion(); calculateSubitem();">
<label>Anzahl</label>
<input v-model="subitem.qtytext">
</div>
<span v-else>{{subitem.qtytext}}</span>
</td>
<td>
<div class="form-group" v-if="crt == si">
<label>Faktor</label>
<input v-model="subitem.factor" @change="calculateSubitem();">
</div>
<span v-else>{{subitem.factor}}</span>
</td>
<td>
<div class="form-group" v-if="crt == si">
<label>EK</label>
<input v-model="subitem.tp1" readonly>
</div>
<span v-else>{{subitem.tp1}}</span>
</td>
<td>
<div class="form-group" v-if="crt == si">
<label>Marge</label>
<input v-model="subitem.margin" readonly>
</div>
<span v-else>{{subitem.margin}}</span>
</td>
<td>
<div class="form-group" v-if="crt == si">
<label>VK</label>
<input v-model="subitem.tp2" readonly>
</div>
<span v-else>{{subitem.tp2}}</span>
</td>
<td>
<div class="form-group" v-if="crt == si">
<label>Rabatt</label>
<input v-model="subitem.discount" @change="calculateSubitem();">
</div>
<span v-else>{{subitem.discount}}</span>
</td>
</tr>
`,
methods: {
calculateSubitem: function() {
if (this.subitem.hasOwnProperty('eprice') && !isNaN(this.subitem.eprice)) {
if (!this.subitem.hasOwnProperty('factor') || isNaN(this.subitem.factor))
this.subitem.factor = 1
if (!this.subitem.hasOwnProperty('discount') || isNaN(this.subitem.discount))
this.subitem.discount = 0
if (!this.subitem.hasOwnProperty('qty') || isNaN(this.subitem.qty))
this.subitem.qty = 0
let discount = 1 - (parseFloat(this.subitem.discount.toString().split(',').join('.')) / 100),
margin = 0
this.subitem.dprice = (this.subitem.eprice.split(',').join('.') * discount)
this.subitem.tp1 = (this.subitem.dprice * this.subitem.qty * this.subitem.factor)
this.subitem.margin = (this.subitem.tp1 * (parseFloat(margin) / 100))
this.subitem.tp2 = (this.subitem.tp1 + this.subitem.margin)
this.$forceUpdate() //{TODO} - find an alternative to $forceUpdate
}
},
parseExpresion: function() {
this.subitem.qty = parseFloat(this.subitem.qtytext.split(',').join('.')) || 0
this.$nextTick(function() {
this.calculateSubitem()
})
}
},
})
Vue.component('subitem-row-sum', {
props: ['sisum'],
template: `
<tr>
<td colspan="3">SUM</td>
<td>
<span>{{sisum.tp1}}</span>
</td>
<td>
<span>{{sisum.margin}}</span>
</td>
<td>
<span>{{sisum.tp2}}</span>
</td>
<td></td>
</tr>
`,
})
Vue.component('html-textarea', {
template: `<div class="html-textarea" contenteditable="true" @input="updateHTML" rows="3"></div>`,
props: ['value'],
mounted: function() {
this.$el.innerHTML = this.value;
},
methods: {
updateHTML: function(e) {
this.$emit('input', e.target.innerHTML)
}
}
})
const app = new Vue({
el: '#app',
data: {
obj: s, // main object for loading
ii: 0, // items index
si: 0, // subitems index
},
computed: {
items: function() {
return this.obj
},
row: function() {
if (!this.items.length)
this.items.push({})
return this.items[this.ii]
},
subitems: function() {
return this.row.subitems
},
srow: function() {
if (!this.subitems.length)
this.subitems.push({})
return this.subitems[this.si]
},
sisum: function() {
debugger;
let sisum = {
tp1: 0,
tp2: 0,
margin: 0
}
this.subitems.forEach(si => {
sisum.tp1 += si.tp1 || 0
sisum.tp2 += si.tp2 || 0
sisum.margin += si.margin || 0
})
return sisum;
}
},
methods: {
setIi: function(i) {
this.ii = i
},
setSi: function(i) {
this.si = i
},
addItemRow: function() {
this.items.push({})
this.setIi(this.items.length - 1)
this.$nextTick(function() {
document.getElementById('items').scrollIntoView({
behavior: "smooth",
block: "end",
inline: "nearest"
})
})
},
addSubitemRow: function() {
this.subitems.push({})
this.setSi(this.subitems.length - 1)
this.$nextTick(function() {
document.getElementById('subitems').scrollIntoView({
behavior: "smooth",
block: "end",
inline: "nearest"
})
})
},
},
})
body {
padding: 0;
margin: 0;
font-size: 14px;
font-family: 'Courier New', monotype;
}
.tables-container {
display: flex;
flex-direction: column;
height: 100vh;
}
.table-container {
height: calc(50% - 2px);
overflow: auto;
margin: 0 0 30px 0;
background: #eee
}
.table-container td {
padding: 3px 6px;
width: 60px;
height: 30px;
border-bottom: 1px solid black;
vertical-align: middle;
font-size: 1.1rem;
}
.html-textarea-container {
position: relative;
}
.html-textarea {
background: white;
border: 1px solid black;
}
.btn-group-edit {
position: absolute;
right: 2px;
bottom: 2px;
/*display: none;*/
z-index: 1;
}
/*.html-textarea:hover + .btn-group-edit,
.html-textarea:focus + .btn-group-edit {
display: block;
}*/
.table-container .form-group>input,
.table-container .form-group>textarea,
.table-container .form-group>select,
.html-textarea {
width: calc(200px - 12px);
height: calc(30px - 6px);
font-size: 1.1rem;
font-family: 'Courier New', monotype;
word-wrap: break-word;
}
.table-container .form-group>textarea,
.html-textarea {
width: calc(600px - 12px);
}
/*.table-container .form-group > textarea:focus,
.html-textarea {
height: calc(150px - 6px);
}*/
.btn-add {
width: 30px;
height: 30px;
padding: 4px 0;
}
<div id="app">
<div class="tables-container">
<div class="table-container table-subitems">
<table id="subitems">
<tr is="subitem-row" v-for="(subitem, i) in subitems" v-bind:subitem="subitem" v-bind:key="i" v-bind:crt="i" v-bind:si="si" v-on:click.native="setSi(i)"></tr>
<tr is="subitem-row-sum" v-bind:sisum="sisum"></tr>
</table>
</div>
<button class="btn-add" v-on:click="addSubitemRow">+</button>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
Source:stackexchange.com