Navigating around potential type errors when passing data for chart.js can be challenging. Here are some strategies to

I'm currently working on an application that includes a chart, and I'm facing an issue while trying to populate the chart with data from my store. The error occurs when I attempt to pass the chartData object through props to the data property of the line Chart (3rd line in the chart component).

Property 'datasets' is missing in type 'Record<string, any>' but required in type 'ChartData<"line", (number | Point | null)[], unknown>'.ts(2741)

index.d.ts(3790, 3): 'datasets' is declared here.

types.d.ts(12, 5): The expected type comes from property 'data' which is declared here on type '{ readonly data: ChartData<"line", (number | Point | null)[], unknown>;'.

The chart component is being rendered in the User.vue file.

    <template>
        <div class="profile-container">
    
            <div class="user-container card">
                <img class="round-image" src="https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_1280.png">
                <div class="username">{{user?.name}}</div>
            </div>
            <div class="card statistics-container">
                <div class="rank"><span><font-awesome-icon class="icon" icon="fa-solid fa-crown" /></span> 2nd place</div>
                <div class="statistics">
                    <div><span>MAX WPM:</span> {{ user?.analytics.max_wpm }}</div>
                    <div><span>AVG WPM:</span> {{ user?.analytics.average_wpm }}</div>
                    <div><span>AVG ACC:</span> {{ user?.analytics.average_accuracy }}%</div>
                    <div><span>TOTAL TESTS:</span> {{ user?.analytics.number_of_tests }}</div>
                </div>
            </div>
            
            <chart class="chart" :chartData="chartData" :chartOptions="chartOptions"></chart>
            
    
        </div>
    </template>
    
    <script setup lang="ts">
        import { ref } from 'vue';
        import Chart from '../components/Profile/Chart.vue'
        import { useUserStore } from '~/store/User/UserStore';
        import {  ChartType } from 'chart.js';
    
        const { $axios } = useNuxtApp();
    
        const userStore = useUserStore();
    
        const showPassword = ref(false);
    
        const chartData = computed(() =>{
            const currentUser = user.value; // Use .value shorthand
            const typingTestResults = currentUser?.typingTestResults;
    
            return {
                type: 'line' as ChartType,
                labels: typingTestResults?.map(result => result.created_at),
                datasets: [
                    {
                        label: 'WPM',
                        data: typingTestResults?.map(result => result.wpm),
                        acc: typingTestResults?.map(result => result.accuracy),
                        time: typingTestResults?.map(result => result.duration_seconds),
                        backgroundColor: 'rgba(255, 174, 0, 0.2)',
                        borderColor: color: 'rgb(255, 174, 0)',
                        borderWidth: 3,
                        pointRadius: 6,
                        tension: 0.1,
                    }
                ],
            };
        });
    
            
        const chartOptions = {
            responsive: true,
            maintainAspectRatio: false,
            scales: {
                x: {
                    title: {
                        display: true,
                        text: 'Dates',
                        font: {
                            size: 16,
                            family: 'RobotoMono'
                        }
                    }
                },
                y: {
                    title: {
                        display: true,
                        text: 'WPM',
                        font: {
                            size: 16,
                            family: 'RobotoMono'
                        }
                    }
                }
            },
            plugins: {
                tooltip: {
                    mode: 'index',
                    intersect: false,
                    callbacks: {
                        label: (context) => {
                            const wpm = `- WPM: ${context.parsed.y}`;
                            const acc = `- ACC: ${context.dataset.acc[context.dataIndex]}%`;
                            const time = `- Time: ${context.dataset.time[context.dataIndex]}s`;
                            return [wpm, acc, time];
                        }
                    },
                    displayColors: false,
                    bodyFont: {
                        size: 17,
                        family: 'RobotoMono'
                    }
                    
                },
                legend: {
                    display: false 
                }
            }
        }
    
        const togglePasswordVisibility = () => {
            showPassword.value = !showPassword.value;
        };
    
        const user = computed(()=>{
            return userStore.user;
        })
    
        onMounted(async () =>{
            if(!userStore.user){
                userStore.user = (await $axios.get('/user')).data.data;
            }
            console.log(user);
        })
    </script>

Here's how my Chart component has been defined:

<template>
    <div>
      <Line :data="chartData" :options="chartOptions"></Line>
    </div>
</template>

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

    ChartJS.register(
        CategoryScale,
        LinearScale,
        PointElement,
        LineElement,
        Title,
        Tooltip,
        Legend
    )

    const props = defineProps({
        chartData: {
            type: Object,
            required: true
        },
        chartOptions: {
            type: Object,
            required: true
        }
    });

And this is how my store looks like:

import { TypingTestResult, User } from './../../types/User';
import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
  state: () => ({
    user: {
      id: 0,
      name: '',
      email: '',
      typingTestResults: [] as TypingTestResult[],
      analytics: {
        max_wpm: 0,
        average_wpm: 0,
        average_accuracy: 0,
        number_of_tests: 0,
      },
    } as User,
  }),
});

Answer №1

Your chart data definition needs to be adjusted due to a bug in the current setup. Here is a revised version that should resolve the issue:

const updatedChartData = computed(() => {
    const currentUser = user.value;
    const typingTestResults = currentUser?.typingTestResults;

    return {
        labels: typingTestResults?.map(result => result.created_at),
        datasets: [
            {
                label: 'WPM',
                data: typingTestResults?.map(result => result.wpm),
                backgroundColor: 'rgba(255, 174, 0, 0.2)',
                borderColor: 'rgb(255, 174, 0)',
                borderWidth: 3,
                pointRadius: 6,
                tension: 0.1
            }
        ],
    };
});

This adjusted code eliminates the additional properties like acc and time within the chart data, fixing the issue you were experiencing.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Send a request from my own local client without encountering any Cross-Origin Resource Sharing (C

I am attempting to send a request from my locally hosted Node.js/Express.js client to a third-party API that I have deployed on the cloud. Strangely, I keep running into a CORS error whenever I make the request. The interesting part is that the request wor ...

The assigned type does not match the type 'IntrinsicAttributes & { children?: ReactNode; }'. This property is not assignable

I have been struggling to resolve this issue, but unfortunately, I have not found a successful solution yet. The error message I am encountering is: Type '{ mailData: mailSendProps; }' is causing an issue as it is not compatible with type &apos ...

Create a function that triggers a fade-out effect on one button when another button is clicked

Hello everyone! I'm still getting the hang of things around here so please be kind. I need some assistance with my weather app project. Specifically, I've created two buttons and I want to make it so that when one is clicked, the other fades to g ...

Why does my event dispatch only run once upon form submission in Svelte JS?

My code successfully fetches data and puts it in a card when new data is added to the input. However, the issue arises when more than one data entry is made - although the data gets added to the database, it does not reflect in the data list. Can anyone he ...

Implementing a strategy to prevent the browser's back button from functioning

Is there a way to prevent the user from using the back button in a single page application? I've tried methods like onhashchange and window.history.forward, but they don't seem to be effective (perhaps because the URL doesn't change). ...

Activating a link click inside a table with jquery

I have been attempting to trigger a click on an anchor within the table compareTable with the code below, however it does not appear to be working as expected. Would anyone be able to provide insight into a possible solution? $('#compareTable a' ...

Dynamic Divider for Side-by-Side Menu - with a unique spin

I recently came across a question about creating responsive separators for horizontal lists on Stack Overflow While attempting to implement this, I encountered some challenges. document.onkeydown = function(event) { var actionBox = document.getElementB ...

Oops! There seems to be an error with the <path> attribute. It looks like we were expecting a number, but received something different: "

I'm currently working on creating a basic line graph using d3.js and integrating it into a React component. However, I'm encountering this error: Error: <path> attribute d: Expected number, "MNaN,36.393574100…" Unfortunately, the similar ...

Is there a way to switch (transpose) the rows and columns of a dynamically generated HTML table from Highchair in Angular 12?

Click here to view the code for creating a highchart table. In the provided example, I have successfully implemented a highchart table using the code below. Highcharts.chart('container', { title: { text: 'Solar Employment Growth by Sec ...

Using AngularJS to bind radio buttons to ng-model

Here is a snippet of my HTML code where I attempted to bind the "formFriendsAll" scope to the ng-model. <form ng-submit="submitForm()" > <div class="col-sm-3"> <div class="form-group"> <label>Which Persons to show?< ...

Tips for successfully implementing Angular.js validation within the confines of a <form> element

Having trouble getting my code to work when I place my app inside the <form name="myForm"> tag. Any suggestions on how to make it function properly? (It works when I place myForm inside ng-app, but my app needs to be within the <form> tag) < ...

What is the best way to bind the value of total when working with forms and the bind method?

I am working on a form where I need to pass the value of total. Regarding the total: I have successfully passed the value of the cart, which is an array. const [total, setTotal] = useState<number | undefined>(undefined); const calculateTotal = () ...

Issue with scroll being caused by the formatting of the jQuery Knob plugin

I am currently utilizing the jQuery Knob plugin and I am looking to have the displayed value shown in pound sterling format. My goal is for it to appear as £123456. However, when I attempt to add the £ sign using the 'format' hook, it causes is ...

In Vue.js, I only want to retrieve and display the parent's ID or name once for each of its child components

<td v-if="currentId != loop.id" class="text-center"> <div :set="currentId = loop.id">{{ loop.id }}</div> </td> <td v-else></td> Looking to achieve a specific layout like this This invo ...

Error message stating 'compression is not defined' encountered while attempting to deploy a Node.js application on Heroku

Why is Heroku indicating that compression is undefined? Strangely, when I manually set process.env.NODE_ENV = 'production' and run the app with node server, everything works perfectly... Error log can be found here: https://gist.github.com/anony ...

Utilizing getServerSideProps in the new app router (app/blah/page.tsx) for maximum functionality

I am a beginner in Next.js and I am currently experimenting with the new app router feature by placing my pages under app/.../page.tsx The code snippet provided works when using the page router (pages/blah.tsx) but encounters issues when used in app/blah/ ...

Tips for creating a TypeScript-compatible redux state tree with static typing and immutability:

One remarkable feature of TypeScript + Redux is the ability to define a statically typed immutable state tree in the following manner: interface StateTree { readonly subState1: SubState1; readonly subState2: SubState2; ...

In my programming world, 'i' is a mysterious being - always undefined, except when it decides

Currently, I am utilizing Vue, Vuedraggable, and Vuetify in my project. I have encountered an issue where I am unable to use 'let' to define the index for my loop as it always returns undefined. Strangely, using 'var' instead of ' ...

The issue with GatsbyJS and Contentful: encountering undefined data

Within the layout folder of my project, I have a Header component that includes a query to fetch some data. However, when I attempt to log this.props.data in the console, all I get is 'undefined'. Could someone please point out where I might be m ...

How can the 'selected' attribute be assigned to 'select/option' tags depending on the option value?

In my code, I have a select input with various options and values. I want to set the 'selected' attribute for the option that corresponds to a specific value X. Here is an example: // If x=3, I want the option with value=3 to be marked as 's ...