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
.