I’m working on a project where I want to add some more input
fields when clicking on a button
.
So I tried jQuery.append
but then there was a problem with v-model
not being detected.
So I tried to achieve the same thing using Vue
if-statement
and I figured out it could be done much simpler by just adding objects to the variable deciding how many input
fields listed in the first place.
But then I noticed something strange and I would like to know if this is by accident or if it’s meant to work this way.
So first of all – this is the html:
<div id="app-edit" class="form-group">
<template v-if="plate.props.products !== undefined">
<div class="form-group form-row" v-for="(extra, index) in plate.props.products">
<div class="col">
<label for="productExtrasNobb0" v-if="index == 0">NOBB number</label>
<input type="text" class="form-control" v-bind:id="'productExtrasNobb' + index" v-model="plate.props.products[index].nobb">
</div>
<div class="col">
<label for="productExtrasAmount0" v-if="index == 0">Amount</label>
<input type="text" class="form-control" v-bind:id="'productExtrasNumber' + index" v-model="plate.props.products[index].number">
</div>
<div class="col-auto d-flex align-items-end">
<button type="button" class="btn btn-danger"><i class="fa fa-minus"></i></button>
</div>
</div>
<template v-if="extraAddons > 0"></template>
<button type="button" class="btn btn-info" @click="addExtra(plate.props.products.length)"><i class="fa fa-plus mr-2"></i>Add</button>
</template>
<template v-else>
<button type="button" class="btn btn-info" @click="addExtra(plate.props.products.length)"><i class="fa fa-plus mr-2"></i>Add</button>
</template>
</div>
And this is the relevant Vue JS:
var app = new Vue({
el: '#app-edit',
data: {
extraAddons: 0,
plate: {
props: {
products: [],
}
}
},
methods: {
addExtra: function(number) {
vm = this;
vm.plate.props.products[number] = {nobb:'',number:''};
vm.extraAddons++;
}
}
});
The thing is this is working fine. When I press the button
to add an extra block it is inserted. But if I remove:
<template v-if="extraAddons > 0"></template>
It’s not working.
Why is that relevant at all? It doesn’t matter what tag I use – it could be p instead of template and still the same result but it seems like the v-if
statement is triggering some sort of rendering?
Could anyone please explain so I can understand better why this is happening?
** UPDATE **
I’ll narrow it down to avoid confusion:
<div id="app-edit" class="form-group">
<template v-if="plate.props.products !== undefined">
<div class="form-group form-row" v-for="(extra, index) in plate.props.products">
</div>
<!-- Without the next line the v-for loop is not re-rendered after adding content to plate.props.products -->
<template v-if="extraAddons > 0"></template>
</template>
<template v-else>
</template>
</div>
Advertisement
Answer
Vue doesn’t notice this:
vm.plate.props.products[number] = {nobb:'',number:''};
because it only notices array mutations made via array methods.
Having the reference to extraAddons
in the loop lets Vue know that something has changed. If you use a mutator like
vm.plate.props.products.splice(number, 1, {nobb:'',number:''});
Vue should behave as expected without your needing to refer to extraAddons
.