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>