espenlg
espenlg

Reputation: 84

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>

Upvotes: 1

Views: 187

Answers (2)

Emad Dehnavi
Emad Dehnavi

Reputation: 3441

Well, you should ask this question first, is my condition going to change often?

well we use v-if if the condition is unlikely to change at runtime since it have higher toggle costs but in your case, the condition changes often so it's not really the best choice, so it's better to use v-show since it's the best option for situations which we need to toggle something very often . the usage of v-show is also the same as v-if.

also is a good idea to read more about Conditional Rendering

Upvotes: 0

Roy J
Roy J

Reputation: 43881

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.

Upvotes: 2

Related Questions