quilkin
quilkin

Reputation: 1427

How to convert vue-chartjs to compositionAPI?

I have been working with vue3 for some months now, and for a new project want to use chart.js - so I found vue-chartjs which I thought would help. The sample shown in the link is written in the 'options' API but I have been working with the 'composition' API so wish to use that with vue-chartjs. Iam also using typescript, but I am getting a ts error with the composition api version, and the code does not run. Here is the original example, with typescript enabled (which still works OK)

<template>
  <Bar
    id="my-chart-id"
    :options="chartOptions"
    :data="chartData"
  />
</template>

<script lang="ts">
import { Bar } from 'vue-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'

ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)

export default {
  name: 'BarChart',
  components: { Bar },
  data() {
    return {
      chartData: {
        labels: [ 'January', 'February', 'March' ],
        datasets: [ { data: [40, 20, 12] } ]
      },
      chartOptions: {
        responsive: true
      }
    }
  }
}
</script>

...and my conversion, using the compostion API:

<script lang="ts">
  import { ref, onBeforeMount } from 'vue'
  import { Bar } from 'vue-chartjs'

  import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'

  const chartData = ref({
          labels: [ 'January', 'February', 'March' ],
          datasets: [ { data: [50, 30, 12] } ]
        });
  const chartOptions = ref( {
          responsive: true
        });
      
  onBeforeMount(() => {
      ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale);
      console.log('bartest: onBeforeMount');
  })
  
</script>

<template>
  <Bar
    :chartOptions = "chartOptions"
    :chartData="chartData"
  />
</template>

but now I have an error on using Bar in the template:

Argument of type '{ chartOptions: { responsive: boolean; }; chartData: { labels: string[]; datasets: { data: number[]; }[]; }; }' is not assignable to parameter of type '{ readonly data: ChartData<"bar", (number | [number, number] | null)[], unknown>; readonly options?: _DeepPartialObject<CoreChartOptions<"bar"> & ElementChartOptions<"bar"> & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...> & BarControllerChartOptions> | undefined; ... 14 more ...; style?:...'. Property 'data' is missing in type '{ chartOptions: { responsive: boolean; }; chartData: { labels: string[]; datasets: { data: number[]; }[]; }; }' but required in type '{ readonly data: ChartData<"bar", (number | [number, number] | null)[], unknown>; readonly options?: _DeepPartialObject<CoreChartOptions<"bar"> & ElementChartOptions<"bar"> & PluginChartOptions<...> & DatasetChartOptions<...> & ScaleChartOptions<...> & BarControllerChartOptions> | undefined; ... 14 more ...; style?:...'.ts(2345)

and also

types.d.ts(12, 5): 'data' is declared here.

types.d.ts suggests that data has a type ChartData but if I try that:

const chartData : ChartData  = ref({....

then I have a different error

Property 'datasets' is missing in type 'Ref<{ labels: string[]; datasets: { data: number[]; }[]; }>' but required in type 'ChartData<keyof ChartTypeRegistry, (number | [number, number] | Point | BubbleDataPoint | null)[], unknown>'.ts(2741)

When I try to run this code, I get:

[Vue warn]: Missing required prop: "data" at <Anonymous chartOptions= {responsive: true} chartData= {labels: Array(3), datasets: Array(1)} > at .....

followed by many subsequent errors.

So, why is the 'options API' version happy without type definitions, and how do I type the 'composition API' version?

Upvotes: 0

Views: 726

Answers (1)

quilkin
quilkin

Reputation: 1427

Thanks to @Estus Flask's comment I have a partial solution - the code now runs, but there is still a typescript error on the 'data' property of Bar:

 <script setup lang="ts">
  import { ref, onBeforeMount } from 'vue'
  import type { Ref } from 'vue'
  import { Bar } from 'vue-chartjs'

  import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, Chart, type ChartData, type ChartOptions } from 'chart.js'

  const chartData = ref({
          labels: [ 'January', 'February', 'March' ],
          datasets: [ { data: [50, 30, 35] } ]
        }) as Ref<ChartData>;
          
  const chartOptions  = ref( {
          responsive: true
        }) as Ref<ChartOptions>;

  onBeforeMount(() => {
    
      ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale);
      console.log('bartest: onBeforeMount');

  })

</script>

<template>
  <Bar
    :options = "chartOptions"
    :data ="chartData"
  />
</template>   

The typescript error is:

Type 'ChartData<keyof ChartTypeRegistry, (number | [number, number] | Point | BubbleDataPoint | null)[], unknown>' is not assignable to type 'ChartData<"bar", (number | [number, number] | null)[], unknown>'.ts(2322) types.d.ts(12, 5): The expected type comes from property 'data' which is declared here on type '{ readonly plugins?: Plugin<"bar", AnyObject>[] | undefined; readonly data: ChartData<"bar", (number | [number, number] | null)[], unknown>; readonly options?: _DeepPartialObject<...> | undefined; ... 13 more ...; style?: unknown; } & Record<...>' (property) data: ChartData<"bar", (number | [number, number] | null)[], unknown>

Upvotes: 1

Related Questions