1

Any help appreciated, I have seen a few post on this subject, but none with a conclusive answer that solves the issue. I have followed all advice in these posts.

I am using ChartJS within a Lightning component. All works fine until I enable Locker Service. I then get the following message in Console and a blank component on the page:

Failed to create chart: can't acquire context from the given item

I am using the latest version of ChartJS: Version: 2.5.0. I'll Post 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);              
}   
})

2 Answers 2

3

I would imagine that document.getElementById("radarChart") is failing. Try printing it out to the console to confirm.

You should use component.find("radarChart").getElement() instead.

And then, there is also a potential timing issue. During the init action, the DOM won't have been created yet. By the time your server action runs its callback, the DOM will probably will be there. But, it might not be. To be on the safe side, I'd create the chart in a custom renderer, on the afterRender event.

3
  • Thanks, for the pointers. Maybe I misunderstand. From looking at the console. It seems that when I add to the afterRender the chart is created sooner. Currently I am doing the init() and creating chart afterScriptsLoaded. From the console it looks like afterScriptsLoaded happens after afterRender. Does this make sense?
    – dacology
    May 5, 2017 at 11:28
  • Well, first try printing the element to the console and see if using .find().getElement() works better for you. As for the order of execution, it's a little bit complicated because it depends how long the server takes to run your Apex and exactly when Lightning allows those callbacks to run. I've not seen documentation guaranteeing an order on it. In my code, I draw the chart in a helper function which checks for all the data I need. I call that function after render and also after the data changes. I exit early from my drawChart() function if the data is not yet available.
    – Aidan
    May 5, 2017 at 12:01
  • Thanks. Yes, I think find().getElement() works better that getElementById, which is contrary to some other posts I have seen.
    – dacology
    May 5, 2017 at 12:45
1

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");

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .