Skip to content
Advertisement

For loop and strange Vue behaviour

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.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement