sveti petar
sveti petar

Reputation: 3797

How to render d3.js chart from vue.js method (passing target div)?

I have my basic vue code that looks like this:

new Vue({

    el : '#friendlist',

    data : {

        friends : []

    },

    methods : {

        fetchStats : function(){

            const axios_data = {
                _token  : $('meta[name="csrf-token"]').attr('content')
            };

            axios.post('/friend-stats/all', axios_data).then(response => {

                this.friends = response.data;

            });

        }
    },

    mounted : function(){

        this.fetchStats();

    },

Now, for each friend in the friends array, I need to render a d3.js chart. I have a method in a different JS file that works correctly, it's called create_spider_chart(friend, target). The friend variable contains a member of the friends array from our vue component above, and target is the target element the chart should be appended to. This is where the problem arises.

If I do this in the response of the axios call:

this.friends = response.data.data;
let target;
for(let i=0;i<this.friends.length;i++){
     target = '.spider-graphic-mini[data-id="'+this.friends[i].id+'"]';
     create_spider_chart(this.friends[i], target);   //d3.js
}

The element .spider-graphic-mini[data-id="'+this.friends[i].id+'"] does exist in the HTML:

<template v-for="(friend,key) in friends">
     <div class="col-md-6 friend-panel p-3">
          <h5>@{{ friend.name }}</h5>
          <div class="spider-graphic-mini mb-4" :data-id="friend.id"></div>
     </div>
</template>

But, when I pass that identifier to the create_spider_chart function, the element apparently doesn't exist. So $(target) has length=0 and the function doesn't know where to create the chart.

How do I get around this?

Upvotes: 0

Views: 441

Answers (1)

Michal Lev&#253;
Michal Lev&#253;

Reputation: 37803

Never used d3 so take this with grain of salt.

JS is single threaded and Vue DOM update process is asynchronous. The moment you assign content into your friends array, Vue had no chance yet to render your template with new data. That's why your element doesn't exist yet.

What you need is to use $nextTick(callback) to essentially way until Vue re-renders your template and run all the code depending on existence of elements inside the callback.

This piece of documentation explains it...

Upvotes: 1

Related Questions