Why does Vue.js lose formatting when adding dynamic items? Is it possible to fix this?

Asked

Viewed 260 times

1

I have a form, where the phone fields is dynamic so the user can add as many numbers as they want.

But when I click the button to add new item, this created item appears without formatting. Not to mention it still gives a bug that goes down the entire screen.

See what happens in the gif below:

inserir a descrição da imagem aqui

I tried to enter the code right here, but it was not showing the formatting of Boostrap, so I put in the codepen:

https://codepen.io/anon/pen/qJYwQL

I know this can happen because Vue.js tried to add an item after the screen was already rendered, I remember that jquery had this same problem, until they launched the live method that kept formatting with dynamic items.

Is it possible to fix this problem in Vue?

2 answers

2


It’s not the problem of Vuejs, the problem is that the Bootstrap cannot "see" the new element, for this it is necessary to (re)start the Bootstrap Material Design every time you add a new element.

One way to do this is to create a custom directive, so every time there is a change in the element, the directive will be responsible for restarting Bootstrap.

Javascript:

Vue.directive('update-material-design', {
  inserted(el) {
    $(el).bootstrapMaterialDesign();
  }
})

HTML:

<div class="row clearfix" v-for="(row, index) in rows" v-update-material-design>

Ready! Now every time a field is added inside the div above, the directive update-material-design will be executed.


Complete Example:

$(document).ready(function() {
  $('body').bootstrapMaterialDesign();
});

var telsadd = new Vue({
  el: "#telsadicionais",
  data: {
    rows: [{
      teltipo: "celtim",
      telddd: "15",
      telnumber: "3429-2410"
    }, {
      teltipo: "whatsapp",
      telddd: "34",
      telnumber: "46536546"
    }]
  },
  methods: {
    addRow: function() {
      this.rows.push({
        teltipo: "",
        telddd: "13",
        telnumber: ""
      });
    },
    removeElement: function(index) {
      this.rows.splice(index, 1);
    }
  }
});

Vue.directive('update-material-design', {
  inserted(el) {
    $(el).bootstrapMaterialDesign();
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/umd/popper.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/js/bootstrap-material-design.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.2/js/bootstrap-select.min.js"></script>

<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/[email protected]/dist/css/bootstrap-material-design.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.2/css/bootstrap-select.min.css" rel="stylesheet"/>


<div id="telsadicionais">
  <div class="row clearfix" v-for="(row, index) in rows" v-update-material-design>
    <div class="col-sm-4">     
      <div class="form-group">
        <div class="form-line">
          <select name="teltipo[]" class="form-control show-tick" title="Tipo" v-model="row.teltipo">
            <option value="fixo">Fixo</option>
            <option value="celvivo">Celular - Vivo</option>
            <option value="celclaro">Celular - Claro</option>
            <option value="celtim">Celular - Tim</option>
            <option value="celoi">Celular - Oi</option>
            <option value="celnextel">Celular - Nextel</option>
            <option value="celoutros">Celular - Outro</option>
            <option value="whatsapp">Whatsapp</option>
          </select>
        </div>
      </div>
    </div>
    <div class="col-sm-1">
<div class="form-group">
    <label for="ddd" class="bmd-label-floating">DDD</label>
    <input type="text" name="telddd[]" class="form-control" maxlength="2" id="ddd" v-model="row.telddd">
  </div>
    </div>
    <div class="col-sm-5">
<div class="form-group">
    <label for="telnumber" class="bmd-label-floating">Numero</label>
    <input type="text" name="telnumber[]" class="form-control" maxlength="12" id="telnumber" v-model="row.telnumber">
  </div>
    </div>
    <div class="col-sm-2">
      <a class="btn btn-primary" v-on:click="removeElement(index);" style="cursor: pointer">Remove</a>
    </div>
  </div>
  <button class="btn btn-primary" @click="addRow">Adicionar</button>
</div>

  • Thank you, it worked perfectly. A simple and easy solution.

1

The Vue does not lose formatting of items added dynamically, however there are some important considerations that are necessary to do with respect to your code:

1- Is highly 'contraindicated' the use of jQuery in projects using Vue or React or Angular, etc... for N reasons.

2- By the link you passed is using the Bootstrap4 with jQuery, and there is the version for Vue which is the one I’m using in the answer.

3- That said, just put one label for the tag select as I did in the example, or, give a margin-top in select with CSS as I did in the example with the buttons remove.

var telsadd = new Vue({
  el: "#telsadicionais",
  data: {
    rows: [{
      teltipo: "celtim",
      telddd: "15",
      telnumber: "3429-2410"
    }, {
      teltipo: "whatsapp",
      telddd: "34",
      telnumber: "46536546"
    }]
  },
  methods: {
    addRow: function() {
      this.rows.push({
        teltipo: "",
        telddd: "13",
        telnumber: "992300312"
      });
    },
    removeElement: function(index) {
      this.rows.splice(index, 1);
    }
  }
});
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css"/>
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.css"/>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

<div id="telsadicionais">
  <div class="row clearfix" v-for="(row, index) in rows">
    <div class="col-sm-4">     
      <div class="form-group">
        <div class="form-line">
          <label>Selecione a operadora</label>
          <select name="teltipo" class="form-control show-tick" title="Tipo" v-model="row.teltipo">
            <option value="fixo">Fixo</option>
            <option value="celvivo">Celular - Vivo</option>
            <option value="celclaro">Celular - Claro</option>
            <option value="celtim">Celular - Tim</option>
            <option value="celoi">Celular - Oi</option>
            <option value="celnextel">Celular - Nextel</option>
            <option value="celoutros">Celular - Outro</option>
            <option value="whatsapp">Whatsapp</option>
          </select>
        </div>
      </div>
    </div>
    <div class="col-sm-1">
<div class="form-group">
    <label for="ddd" class="bmd-label-floating">DDD</label>
    <input type="text" name="telddd[]" class="form-control" maxlength="2" id="ddd" v-model="row.telddd">
  </div>
    </div>
    <div class="col-sm-5">
<div class="form-group">
    <label for="telnumber" class="bmd-label-floating">Numero</label>
    <input type="text" name="telnumber[]" class="form-control" maxlength="12" id="telnumber" v-model="row.telnumber">
  </div>
    </div>
    <div class="col-sm-2">
      <a class="btn btn-danger" v-on:click="removeElement(index);" style="cursor: pointer;margin-top:30px;">Remove</a>
    </div>
  </div>
  <button class="btn btn-primary" @click="addRow">Adicionar</button>
</div>

Here are some CSS frameworks links for use with Vue.js

  • Thank you for answering. At the moment I can’t change the frameworks that are already being used in the project. The other answer I selected as correct helped me better in this case without having to change libraries. But I still loved yours

  • 1

    For nothing Samantha, jewel who liked the links.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.