Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dynamically create a new div using v-for in Vue.js?

I want to create div's dynamically based on the number of elements present in an array. The div's contain the html element created by ProgressBar.js.

This the Vue.js code

import ProgressBar from 'progressbar.js'
var bar;

export default {
    data() {
        return {
            fitness: ['Run', 'Cycle'],
            val: 0.65
        }
    },

    mounted(){
        this.showProgressBar(this.val);
    },


    created: function() {

    },

    methods:{
         showProgressBar: function(val){
            new ProgressBar.Circle('#container',{
                trailColor: 'gainsboro',
                trailWidth: 20,
                color: 'teal',
                strokeWidth: 20
            }).animate(val); 
         }
    }
}
<div class="content" v-for="fitness in fitness">
  <span>{{ fitness }}</span>
  <div id="container"></div>
</div>

Since an id is associated with only one div, I am not able to execute a new ProgressBar.Circle object that would create another div. Is there a way to dynamically create a new div with different a id inside the v-for every time the new ProgressBar.circle is executed? Can somenone please help me out here?

like image 529
CoderPJ Avatar asked Aug 16 '17 18:08

CoderPJ


People also ask

How can you add new DIV elements dynamically?

New elements can be dynamically created in JavaScript with the help of createElement() method. The attributes of the created element can be set using the setAttribute() method.

What is a dynamic Div?

Dynamic disks are logical disks that have the ability to utilize multiple hard disks in the computer to provide disk redundancy and mirroring as well as an increase in performance and reliability.

What is V Pre in VUE JS?

The v-pre directive is a Vue. js directive used to skip compilation for this element and all its children. You can use this for displaying raw mustache tags. First, we will create a div element with id as app and let's apply the v-pre directive to an element. Further, we can use a heading element to show the data.

Can I use DOM in Vue?

If a ref attribute is added to an HTML element in your Vue template, you'll then be able to reference that element or even a child element in your Vue instance. You can also access the DOM element directly, too; it is a read-only attribute and returns an object.


2 Answers

Here is a re-usable component that wraps progressbar.js.

<template>
  <div class="container"><div ref="bar"></div></div>
</template>
<script>
  import ProgressBar from "progressbar.js"

  export default {
    props:["options", "val"],
    mounted(){
      new ProgressBar.Circle(this.$refs.bar, this.options).animate(this.val)
    } 
  }
</script>
<style>
  .container{
    width:100px; 
    height: 100px
  }
</style>

Here is how it's used in a template:

<div v-for="fit in fitness" class="fitness">
  <div>{{fit.name}}</div>
  <progress-bar :val="fit.val" :options="options"></progress-bar>
</div>

Working Example.

like image 186
Bert Avatar answered Oct 23 '22 22:10

Bert


One solution could be give unique ids to each container div and create progress bars for each of them.

Try the code below -

import ProgressBar from 'progressbar.js'
var bar;

export default {
  data() {
    return {
      fitness: ['Dietary Intake', 'Exercise'],
      val: [0.65, 9]
    }
  },

  mounted() {
    this.showProgressBar();
  },


  created: function() {

  },

  methods: {
    showProgressBar: function() {
      this.fitness.forEach((f, i) => {
        new ProgressBar.Circle('#container-' + i, {
          trailColor: 'gainsboro',
          trailWidth: 20,
          color: 'teal',
          strokeWidth: 20
        }).animate(this.val[i]);
      });

    }
  }
}
<div class="content" v-for="(f, index) in fitness">
  <span>{{ f }}</span>
  <div v-bind:id="`container-${index}`"></div>
</div>

Update - val can be an array. And its values can be referenced from the within the showProgressBar function.

I am assuming the length of fitness and val arrays are the same.

Update 2 - Explanation.

So basically there are 2 main issues here that have to addressed.

1. Generating multiple container divs

We need to generate multiple container divs as there are going to be multiple ProgressBars. But we need to distinguish between them so we create a unique id for each of them. That is what the following code does.

<div class="content" v-for="(f, index) in fitness">
  <span>{{ f }}</span>
  <div v-bind:id="`container-${index}`"></div>
</div>

Since index numbers are unique. Adding them to "container" generated unique ids. See List Rendering

2. Generate multiple ProgressBars when component mounts.

This is simpler we simple create new ProgressBar for each "fitness" value.

this.fitness.forEach((f, i) => {
  new ProgressBar.Circle('#container-' + i, {
    trailColor: 'gainsboro',
    trailWidth: 20,
    color: 'teal',
    strokeWidth: 20
  }).animate(this.val[i]);

Refer - Array forEach

like image 3
Yasser Hussain Avatar answered Oct 23 '22 21:10

Yasser Hussain