eChart Display Issues in Tabs

I love Vue / Vuetify and use them quite often in my projects.

I had to display charts in a couple of recent projects and my search led to v-charts. I was impressed with what the library could do -

  • v-charts is a Vue wrapper for eCharts, the Baidu-developed chart library
  • The v-charts library makes it really easy to use ECharts. Docs have improved significantly after transitioning to be an Apache incubator
  • Charts are amazing. They are responsive and reactive without needing any additional work

So then, I was within reach of nirvana in my ‘pursuit of excellence’ in development of typical data-driven applications.. .. until I came across an issue with displaying charts in tabs.

Consider a typical example. We have to display eCharts in ‘Posts’ and ‘Comments’ components. These components are housed in two tabs in the same page.

<template>
  <div>
    <v-tabs slot="extension">
      <v-tabs-slider></v-tabs-slider>

      <v-tab v-for="(item,index) in tabItems" :key="index">
        {{ item.text }}
      </v-tab>

      <v-tab-item>
        <Posts></Posts>         <!-- has posts chart --!>
      </v-tab-item>
      <v-tab-item>
        <Comments></Comments>      <!-- has comments chart --!>
      </v-tab-item>
    </v-tabs>
  </div>
</template>

v-chart/eChart is displayed as expected on the first tab (for e.g. Posts). However, switching to ‘Comments’ will not render the eChart component on that tab.

It was also observed that -

  1. Any tab apart from the active tab does not display the chart
  2. No amount of changing chart options or containers, or playing around with ‘mounted()’ / ‘created()’ will help
  3. Any change to the tab/component and subsequent hot reload will magically make the chart appear while in development mode

I think the problem was in eCharts trying to render at page render, and refusing to react to tab changes in the same page.

While the first tab and associated chart got created alongside the page itself, the other tabs are not so lucky. In other words, the parent div is zero and eChart does not automatically render when the parent div changes with a different tab.

The solution turned out to be quite simple. Just instruct Vue to create component within a tab when selected and not when the parent tab is rendered.

Change the above code to -

<template>
  <div>
    <v-tabs slot="extension" v-model="tabs"> <!-- declare tabs in data --!>
      <v-tabs-slider></v-tabs-slider>

      <v-tab v-for="(item,index) in tabItems" :key="index">
        {{ item.text }}
      </v-tab>
    </v-tabs>

    <v-tabs-items v-model="tabs">
      <v-tab-item>
        <Posts></Posts>         <!-- has posts chart -->
      </v-tab-item>
      <v-tab-item v-if="tabs==1">
        <Comments></Comments>   <!-- has comments chart --!>
      </v-tab-item>
    </v-tabs-items>
  </div>
</template>

The ‘Comments’ component will now get mounted only if the v-if gets satisfied. eChart within that component will also get rendered at that time, and properly react to the tab clicks.

And so it happened that the world moved to a better place from where it was.

comments powered by Disqus