
Hello, and welcome to Another Salesforce Blog! Here I will be posting solutions to problems that I couldn’t find an answer to in hopes of helping those who find themselves stuck when using the Salesforce platform.
User Story
We have some information on our objects that we want to view in dynamic charts. These charts will update based on the object that is created by inputting a sentence into a Lightning Web Component.
Background
In the previous post, we started on our Lightning Web Component. We are going to use Chart.js to create a truly dynamic dashboard for our existing LWC.

Solution
The full code for Parts One and Two can be found at my GitHub repository here.
Step One – Download and Install Chart.js.
This one is pretty easy. We’re going to download Chart.js and install it into our Salesforce org. We will do this by uploading the file as a Static Resource.
Navigate to the Installation page on Chart.js and scroll to the GitHub section. Follow the link to navigate to the newest version of the source code on GitHub.

Once on the GitHub page, download and unzip the Source Code zip.

There will be a number of folders and files, but the one we need is the dist
folder. We are going to zip the files within folder and upload the .zip
file as a Static Resource called chartJs
. Be sure to create your .zip
file with just the files contained within the dist
folder! If you zip the whole dist
folder, you’ll get stuck in a few minutes.

chartJs
.This will allow us to use the files provided to us by Chart.js in Salesforce.
Step Two – Update Apex Class createSentence.cls
.
Before we dive into the JavaScript, let’s update our Apex class. We need a new @AuraEnabled
method to retrieve information from our Sentence__c
object that is created based on information that is sent to us from our LWC. Add the following below your insertSentence
method:
@AuraEnabled(cacheable=true) public static Sentence__c getChartSentence(String recordId){ Sentence__c returnSentence = [SELECT Id, Name, Sentence__c, IsPalindrome__c, A__c, B__c, C__c, D__c, E__c, F__c, G__c, H__c, I__c, J__c, K__c, L__c, M__c, N__c, O__c, P__c, Q__c, R__c, S__c, T__c, U__c, V__c, W__c, X__c, Y__c, Z__c, x0__c, x1__c, x2__c, x3__c, x4__c, x5__c, x6__c, x7__c, x8__c, x9__c FROM Sentence__c WHERE Id = :recordId LIMIT 1]; return returnSentence; }
Step Three – Create Donut Chart Lightning Web Component.
Next, we’re going to create our second Lightning Web Component. This LWC will be nested inside of our palindromeChecker
. We’ll call our new component sentenceDonutChart
, and we will use this component to display the number of letters in our sentence.
We’ll start by creating our HTML file.
<template> <div class="chart slds-var-m-around_medium" lwc:dom="manual"></div> </template>
This one is pretty simple, we’re just going to create a chart div
, and we’ll place this inside our parent LWC.
We will do this by adding the following element below our first column element, which will send our sentenceId
from Part One to the char element:
<div class="slds-col slds-size_1-of-3"> <c-sentence-donut-chart sentence-id={sentenceId}></c-sentence-donut-chart> </div>
For now, we won’t see anything when we deploy and refresh our page, so let’s build our chart.
Navigate to the sentenceDonutchart.js
file, and enter the following:
import { LightningElement, api, track, wire } from 'lwc'; import { loadScript, loadStyle } from 'lightning/platformResourceLoader'; import chartjs from '@salesforce/resourceUrl/chartJs'; import getChartSentence from '@salesforce/apex/createSentence.getChartSentence'; export default class LibsChartjs extends LightningElement { //receive parentId from parent LWC @api sentenceId; @track sentence; error; @track chart; chartjsInitialized = false; //configuration variable config = { type: 'doughnut', data: { datasets: [ { data: [], backgroundColor: [ 'rgb(192, 11, 92)', 'rgb(191, 97, 215)', 'rgb(69, 15, 36)', 'rgb(197, 86, 186)', 'rgb(56, 7, 41)', 'rgb(124, 68, 225)', 'rgb(26, 243, 223)', 'rgb(159, 198, 55)', 'rgb(167, 69, 94)', 'rgb(173, 151, 102)', 'rgb(89, 106, 124)', 'rgb(69, 203, 69)', 'rgb(16, 72, 90)', 'rgb(176, 80, 1)', 'rgb(215, 6, 2)', 'rgb(137, 187, 127)', 'rgb(81, 113, 162)', 'rgb(230, 222, 86)', 'rgb(82, 239, 17)', 'rgb(226, 125, 8)', 'rgb(237, 241, 14)', 'rgb(40, 67, 192)', 'rgb(21, 85, 148)', 'rgb(162, 232, 153)', 'rgb(213, 45, 249)', 'rgb(186, 252, 119)' ], label: 'Sentence' } ], labels: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] }, options: { responsive: true, legend: { display: false }, animation: { animateScale: true, animateRotate: true } } }; //wired function @wire(getChartSentence, {recordId: '$sentenceId'}) wiredSentence({data, error}) { if(data) { this.sentence = data; //clear previous data this.config.data.datasets[0].data.length = []; this.config.data.datasets[0].data.push(data.A__c); this.config.data.datasets[0].data.push(data.B__c); this.config.data.datasets[0].data.push(data.C__c); this.config.data.datasets[0].data.push(data.D__c); this.config.data.datasets[0].data.push(data.E__c); this.config.data.datasets[0].data.push(data.F__c); this.config.data.datasets[0].data.push(data.G__c); this.config.data.datasets[0].data.push(data.H__c); this.config.data.datasets[0].data.push(data.I__c); this.config.data.datasets[0].data.push(data.J__c); this.config.data.datasets[0].data.push(data.K__c); this.config.data.datasets[0].data.push(data.L__c); this.config.data.datasets[0].data.push(data.M__c); this.config.data.datasets[0].data.push(data.N__c); this.config.data.datasets[0].data.push(data.O__c); this.config.data.datasets[0].data.push(data.P__c); this.config.data.datasets[0].data.push(data.Q__c); this.config.data.datasets[0].data.push(data.R__c); this.config.data.datasets[0].data.push(data.S__c); this.config.data.datasets[0].data.push(data.T__c); this.config.data.datasets[0].data.push(data.U__c); this.config.data.datasets[0].data.push(data.V__c); this.config.data.datasets[0].data.push(data.W__c); this.config.data.datasets[0].data.push(data.X__c); this.config.data.datasets[0].data.push(data.Y__c); this.config.data.datasets[0].data.push(data.Z__c); this.chart.update(); } else if(error) { this.error = error; } } updateChart() { this.chart.update(); } renderedCallback() { if (this.chartjsInitialized) { return; } Promise.all([ loadScript(this, chartjs + '/Chart.min.js'), loadStyle(this, chartjs + '/Chart.min.css') ]) .then(() => { // disable Chart.js CSS injection window.Chart.platform.disableCSSInjection = true; const canvas = document.createElement('canvas'); this.template.querySelector('div.chart').appendChild(canvas); const ctx = canvas.getContext('2d'); this.chart = new window.Chart(ctx, this.config); }) .catch((error) => { this.error = error; alert(this.error); }); this.chartjsInitialized = true; } }
Step Three – Create Bar Chart Lightning Web Component.
Lastly, we’re going to create our third Lightning Web Component. This LWC will be nested inside of our palindromeChecker
along with our sentenceDonutChart
. We’ll call our new component sentenceBarChart
, and we will use this component to display the number of numerical characters in our sentence.
We’ll start with our HTML file, which should look familiar!
<template> <div class="chart slds-var-m-around_medium" lwc:dom="manual"></div> </template>
Next, we’ll go to our sentenceBarChart.js
file and use the following:
import { LightningElement, api, track, wire } from 'lwc'; import { loadScript, loadStyle } from 'lightning/platformResourceLoader'; import chartjs from '@salesforce/resourceUrl/chartJs'; import getChartSentence from '@salesforce/apex/createSentence.getChartSentence'; export default class LibsChartjs extends LightningElement { //receive parentId from parent LWC @api sentenceId; @track sentence; error; @track chart; chartjsInitialized = false; @track maxvalue; //configuration variable config = { type: 'bar', data: { datasets: [ { data: [], backgroundColor: [ 'rgb(192, 11, 92)', 'rgb(191, 97, 215)', 'rgb(69, 15, 36)', 'rgb(197, 86, 186)', 'rgb(56, 7, 41)', 'rgb(124, 68, 225)', 'rgb(26, 243, 223)', 'rgb(159, 198, 55)', 'rgb(167, 69, 94)', 'rgb(173, 151, 102)' ], label: 'Numerical Characters' } ], labels: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] }, options: { scales: { yAxes: [{ ticks: { min: 0, stepSize: 1 } }] }, legend: { display: false } } }; //wired function @wire(getChartSentence, {recordId: '$sentenceId'}) wiredSentence({data, error}) { if(data) { this.sentence = data; //clear previous data this.config.data.datasets[0].data.length = []; this.config.data.datasets[0].data.push(data.X0__c); this.config.data.datasets[0].data.push(data.X1__c); this.config.data.datasets[0].data.push(data.X2__c); this.config.data.datasets[0].data.push(data.X3__c); this.config.data.datasets[0].data.push(data.X4__c); this.config.data.datasets[0].data.push(data.X5__c); this.config.data.datasets[0].data.push(data.X6__c); this.config.data.datasets[0].data.push(data.X7__c); this.config.data.datasets[0].data.push(data.X8__c); this.config.data.datasets[0].data.push(data.X9__c); this.chart.update(); } else if(error) { this.error = error; alert('wired error') } } updateChart() { this.chart.update(); } renderedCallback() { if (this.chartjsInitialized) { return; } Promise.all([ loadScript(this, chartjs + '/Chart.min.js'), loadStyle(this, chartjs + '/Chart.min.css') ]) .then(() => { // disable Chart.js CSS injection window.Chart.platform.disableCSSInjection = true; const canvas = document.createElement('canvas'); this.template.querySelector('div.chart').appendChild(canvas); const ctx = canvas.getContext('2d'); this.chart = new window.Chart(ctx, this.config); }) .catch((error) => { this.error = error; alert(this.error); }); this.chartjsInitialized = true; } }
Now, when we deploy and refresh our page, we should get something like this:

So, why does this work?
In order to make the chart responsive to the input into our LWC, we need to use the .push()
function to update our configuration object for our charts.
You’ll notice that in the JavaScript file for each chart, config.data.datasets[0].data
starts as an empty array:

We then .push()
our dataset into that array, and update the chart. When we get a new set of data, we clear the array by setting it to an empty array once again.
Thanks for reading, let me know if you have any comments or questions!

Evelyn Grizzle
Another Salesforce Blog
