Lightning Aura Components – Fixing Caching, Reload, and Render Issues with ChartJS

I have a Lightning component that displays a chart with ChartJS.
I am in an org with Locker Service disabled.

I have designed the Lightning component for reuse, so that I can use the same component on a Home Page and also on a Record Detail Page. (The apex controller that generates the data returns appropriate data based on the context).

When I display the chart on the Home page it shows data relating to all Accounts, but when the chart is displayed on an Account Record page it displays data relevant to just that account.

The charts work correctly in isolation, the problem is that when navigating from a home page to a record page (or the reverse) the component will not display on the second view, the component remains as white space on the page. When I perform a forced refresh (ctrl + R) then the chart does then render.

The correct data is present when I console.log, but the chart does not render.

I am not sure if the problem lies within some cache element of Lightning? Or with ChartJS and the html Canvas element?

Code below:

Component:

<aura:component controller="SentimentChartData" implements="force:appHostable,flexipage:availableForAllPageTypes,force:hasRecordId,force:hasSObjectName" access="global">
<aura:attribute name="recordId" type="String"/>
<ltng:require scripts="{!$Resource.chart_js}" afterScriptsLoaded="{!c.init}"/>  
<ui:outputText class="form-control" aura:id="recid" value="{!v.recId}" />        
<div>  
    <canvas aura:id="radarChart" id="radarChart" width="200" height="200"/>
</div>

Controller:

({
    init : function(component, event, helper) { 
    helper.setupRadarChart(component);
}
})

Helper:

({
setupRadarChart : function(component) {
    var jsonRetVal;
    var rId = component.get("v.recordId");
    var action = component.get("c.buildRadarData");
    action.setParams({
        "rId": rId
    });

    action.setCallback(this, function(a){
        jsonRetVal = JSON.parse(a.getReturnValue()); 

        var data =  jsonRetVal; 

        var ctx = document.getElementById("radarChart");            
            var myRadar = new Chart(ctx, {
                type: "radar",
                data: data,
                options: {
                    scale: {
                        reverse: false,
                        ticks: {
                            beginAtZero: true
                        }
                    }
                }
            }); 
    });
    $A.enqueueAction(action);              
}   
})

Best Answer

In the end I was able to get this working with the following 2 changes:

  1. I switched to v2.3 of ChartJS (maybe 2.4 would have worked also). Either there is a bug in 2.5 or it is not compatible with the way I am using it.
  2. I replaced the code to get the Canvas element as below, previously using getElementById. (This is contrary to a number of other posts that say that the getContext("2d") does not work with LockerService.)

    var el = component.find("radarChart").getElement(); var ctx = el.getContext("2d");