0

I implemented chart.js lightning web component in Salesforce home page. It sometimes loads properly, sometimes loads blank and sometimes loads partially (chart with no data) and then it can appear after I resize a browser window.

When I hardcoded data in javascript then it loaded fine everytime, but when I changed to apex method to feed data then it looks like it renders too fast (when data are not ready?) and then it is what it is.

What is more when I reload page with browser reload - it rarely loads corerctly, but when I click "Home" tab in salesforce then it loads fine most of the times.

Any ideas what's wrong and how to fix it?

My Apex method return Map<String,Decimal>.

javascript:

import { LightningElement, track, wire } from 'lwc';
import { loadScript } from 'lightning/platformResourceLoader';
import ChartJs from '@salesforce/resourceUrl/ChartJsNew';
import Id from '@salesforce/user/Id';
import getvaluesMapUser from '@salesforce/apex/userChart_Util.getValuesMapUser';


export default class userChart extends LightningElement {
    
    isChartJsInitialized = false;
    chartLabels=[];
    chartValues=[];
    displayChart = false;
    
    userId = Id;

    @wire(getvaluesMapUser, { userId: '$userId' })
    wiredValuesMap({ data, error }) {
        if (data) {
            const valuesMap = data;
            console.log(valuesMap);

            for (const key in valuesMap) {
                this.chartLabels.push(key);
                this.chartValues.push(valuesMap[key]);
            }

            if(Object.keys(valuesMap).length > 0){
                this.displayChart = true;
            } else {
                this.displayChart = false;
            }
            
        } else if (error) {
            console.log('Error getting values map user');
            console.error(error);
        }
    }

    
    renderedCallback() {
        if (this.isChartJsInitialized) {
            return;
        }
        this.isChartJsInitialized = true;
        Promise.all([
        loadScript(this, ChartJs)
        ])
        .then(() => {
            // Chart.js library loaded
            this.initializeChart();
        })
        .catch(error => {
        console.log('Error loading Chart.js');
        console.error(error);
        });
    }

    initializeChart() {
        const ctx = this.template.querySelector('canvas').getContext('2d');
        new window.Chart(ctx, {
            data: {
                labels: this.chartLabels,
                datasets: [
                    {
                        label: 'Values',
                        data: this.chartValues,
                        backgroundColor: 'rgba(14, 112, 199, 1)',
                        borderColor: 'rgba(14, 112, 199, 1)',
                        type: 'bar',
                        borderWidth: 1,
                        order: 1
                    }
                ]
            },
            options: {
                responsive: true,
                scales: {
                    y: {
                        beginAtZero: true
                    }
                }
            },
        });
    }
}

html:

<template>
        <template lwc:if={displayChart}>
            <lightning-card title="Values Chart" icon-name="custom:custom17">
                <div>
                    <canvas id="chart"></canvas>
                </div>
            </lightning-card>
        </template>
        <template lwc:else>
            <lightning-card title="Values Chart" icon-name="custom:custom17">
                <div class="slds-m-around_medium">
                    <p>No Data To Display</p>
                </div>
            </lightning-card>
        </template>
</template>
New contributor
user31943000 is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

1 Answer 1

1

Well it seems like your canvas is not set with data because those have not been fetched yet, therefore you potentially go to an error; when I replicated it I got this:

TypeError: Cannot read properties of null (reading 'getContext')
    at y.initializeChart (testChart.js:1:1630)
    at eval (testChart.js:1:1439)
eval @ testChart.js:1
Promise.catch
renderedCallback @ testChart.js:1

I guess you can do a hack to determine if the canvas is present in the DOM at the time since you already have the displayChart attribute and cause a small delay if it isn't.

renderedCallback() {
        if (this.isChartJsInitialized) {
            return;
        }

        if (!this.displayChart) {
            return;
        }

        this.isChartJsInitialized = true;
        Promise.all([
            loadScript(this, ChartJs)
        ])
        .then(() => {
            const canvas = this.template.querySelector('canvas');
            if (!canvas)
                setTimeout(() => this.initializeChart(), 0);
            else
                this.initializeChart();
        })
        .catch(error => {
            console.log('Error loading Chart.js');
            console.error(error);
        });
    }

I wouldn't say this is the optimal solution, but this solved the issue for me.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, this solved the problem! Sice I have many different standard charts on a homepage then whole page loads very slowly. When I add 1000ms delay, it loads perfectly on time!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.