Reputation: 708
I'm trying to create a Chart.vue
component based on D3. I need to be able to add multiple instances to a single page and keep each one separate.
I've tried to assign an ID generated with uuid
to the div wrapping my component in the template:
<template>
<div :id=this.id>
<svg></svg>
</div>
</template>
The ID is created when the component is created.
<script>
import * as d3 from "d3";
import { v4 as uuidv4 } from "uuid";
export default {
...
created () {
this.id = uuidv4()
},
...
The chart is re-rendered when there is an update to the data passed in as props
from the parent App.vue
. To select the "correct" <svg>
element that is owned by a particular instance of Chart
I use the unique this.id
in my renderChart
method:
methods: {
renderChart(chart_data) {
const svg_width = 1000;
const svg_height = 600;
const svg = d3
.select("#" + this.id)
.select("svg")
.attr("width", svg_width)
.attr("height", svg_height);
...
Proceeding to add all the axes, data, etc.
If I add two such components to my App.vue
template:
<template>
<div id="app">
<form action="#" @submit.prevent="getIssues">
<div class="form-group">
<input
type="text"
placeholder="owner/repo Name"
v-model="repository"
class="col-md-2 col-md-offset-5"
>
</div>
</form>
<Chart :issues="issues" />
<Chart :issues="issues" />
</div>
</template>
I see that they are added to the DOM with some uuid
that's been created. When the data is updated and the renderChart
function executes, both components get a copy of the "issues"
data, but I only see one chart being created.
I'm quite novice with JavaScript, Vue and D3, so perhaps going about this the wrong way, but it seems like this should work?
Any help is appreciated.
Upvotes: 0
Views: 774
Reputation: 708
Well, I seem to have found a solution, although I don't fully understand it, and I'm not sure why the initial approach didn't work (note: original approach did seem to work sometimes, but the behaviour was unpredictable).
To solve, I pass a unique ID to the component from the parent template as a prop and add it as the Chart component <div>
id.
In App.vue
:
<template>
<div id="app">
<form action="#" @submit.prevent="getIssues">
<div class="form-group">
<input
type="text"
placeholder="owner/repo Name"
v-model="repository"
class="col-md-2 col-md-offset-5"
>
</div>
</form>
<Chart id="chart1" :issues="issues" />
<Chart id="chart2" :issues="issues" />
</div>
</template>
Now I need to add id
in the props
of the Chart.vue
and set a variable in the data()
section.
<template>
<div :id=chart_id>
<svg></svg>
</div>
</template>
<script>
import * as d3 from "d3";
export default {
name: 'Chart',
props: ["issues", "id"],
data() {
return {
chart: null,
chart_id: this.id
};
},
...
I'm not sure why the uuid approach didn't work, but this seems more robust.
Upvotes: 0