Home > database >  How to append component as a child dynamically
How to append component as a child dynamically

Time:09-15

I'm creating chart generator and I need to let user adding and removing charts from the view. Is it possible to use function appendChild() or something similar to do it dynamically? Here is a short preview what I want to do:

<template>
  <div >
    <div :ref="`chart${index}`"  v-for="index in 6" :key="index">
      <i @click="addChart(index)" ></i>
    </div>
  </div>
</template>

<script>
import 'primeicons/primeicons.css';
import BaseChart from '@/components/charts/BaseChart.vue'
export default {
  components: {
    BaseChart
  },
  methods: {
    addChart(index) {
      this.$refs[`chart${index}`].appendChild(BaseChart, props)
    }
  },
}
</script>

CodePudding user response:

Try not to do direct DOM manipulation if you can. There is almost always a better way with Vue. In your case, a simple array can hold true/false values for conditionally displaying a chart underneath your add/remove buttons. The buttons toggle the appropriate array value, and the chart only displays if that value is true using v-if

<template>
  <div >
    <div  v-for="index in 6" :key="index">
      <i @click="addChart(index)" >click me</i>
      <i @click="removeChart(index)" >remove me</i>
      <BaseChart v-if="chartArray[index]" />
    </div>
  </div>
</template>
<script>
import 'primeicons/primeicons.css';
import BaseChart from '@/components/charts/BaseChart.vue'
export default {
  components: {
    BaseChart,
  },
  data() {
    return {
      chartArray: [],
    };
  },
  methods: {
    addChart(index) {
      this.$set(this.chartArray, index, true);
    },
    removeChart(index) {
      this.$set(this.chartArray, index, false);
    },
  },
};
</script>

The this.$set() syntax comes from Vue 2's method for updating array values by index while maintaining reactivity

CodePudding user response:

in my opinion, one of the best solutions is to create an array with graphs, the elements of which will contain a flag that allows you to adjust the display of each graph. The final version will look approximately like this.

<template>
  <div >
    <div
      
      v-for="chart in charts"
      :key="chart.id"
    >
      <BaseChart v-if="chart.isShown" />
      <i
        v-if="!chart.isShown"
        @click="addChart(chart.id)"
        
        > </i
      >
      <i
        v-else
        @click="removeChart(chart.id)"
        
        >-</i
      >
    </div>
  </div>
</template>

<script>
import BaseChart from "@/components/charts/BaseChart.vue";
export default {
  components: {
    BaseChart,
  },
  data() {
    return {
      charts: [
        {
          id: 1,
          isShown: true,
        },
        {
          id: 2,
          isShown: true,
        },
        {
          id: 3,
          isShown: true,
        },
        {
          id: 4,
          isShown: true,
        },
        {
          id: 5,
          isShown: true,
        },
        {
          id: 6,
          isShown: true,
        },
      ],
    };
  },
  methods: {
    addChart(id) {
      const chart = this.charts.find((chart) => chart.id === id);
      if (chart) {
        chart.isShown = true;
      }
    },
    removeChart(id) {
      const chart = this.charts.find((chart) => chart.id === id);
      if (chart) {
        chart.isShown = false;
      }
    },
  },
};
</script>

This solution is applicable for a fixed array length. If you plan to create an unlimited number of graphs, then the code will have to be changed. In this case, we cannot use the index as a key when iterating through v-for. When adding a new element, you need to generate a unique id and add a new element to the array. To delete an element, you just need to filter the current array by the element id.

<template>
  <div >
    <div
      
      v-for="chart in charts"
      :key="chart.id"
    >
      <BaseChart />
      <i @click="removeChart(chart.id)" 
        >-</i
      >
    </div>
    <i @click="addChart()" > </i>
  </div>
</template>

<script>
import BaseChart from "@/components/charts/BaseChart.vue";

export default {
  components: {
    BaseChart,
  },
  data() {
    return {
      charts: [],
    };
  },
  methods: {
    addChart(id) {
      const biggestId = this.charts.reduce(
        (acc, rec) => (acc.id > rec.id ? acc.id : rec.id),
        0
      );
      this.charts.push({ id: biggestId   1 });
    },
    removeChart(id) {
      this.charts = this.charts.filter((chart) => chart.id !== id);
    },
  },
};
</script>
  • Related