javascriptangularjsangular-uichart.jsangular-ui-tabset

Chart.js in AngularJS tabset does not render


I am using a AngularJS module based on Chart.js to display graph. It works like a charm, but when I display a chart in a AngularJS tabset, the graph does not render if it is not the first tab.

  <tabset>
    <tab heading="Tab 1">
        <!-- OK -->
        <canvas class="chart chart-pie" data="[140, 160]" labels="['d1', 'd2']" legend="true"></canvas>
    </tab>
    <tab heading="Tab 2">
        <!-- Does not render -->
       <canvas class="chart chart-pie" data="[140, 160]" labels="['d1', 'd2']" legend="true"></canvas>
    </tab>
  </tabset>

This is the JSFiddle. Does anyone manage to fix this ?

Thanks


Solution

  • As @Martin pointed it out, it is an issue of Chart.js not showing the chart when initiliazed in a hidden DOM element (its height and width remain at 0px even after showing the hidden element).

    This issue is tracked here.

    I share you my home made solution if you are blocked by components like tabs initialized hidden. I have created a directive in which I compile the canvas element. In order to be able to refresh the element when needed (eg when the tab is opened), I watch an attribute I will manually change on tab change in my controller.

    Here is my directive :

    app.directive('graphCanvasRefresh', ['$compile', function($compile) {
    function link(scope, elem, attrs) {
    
        function refreshDOM() {
            var markup = '<canvas class="chart chart-pie" id="graph" data="entityGraph.data" labels="entityGraph.labels" legend="true" colours="graphColours" ></canvas>';
            var el = angular.element(markup);
            compiled = $compile(el);
            elem.html('');
            elem.append(el);
            compiled(scope);
        };
    
        // Refresh the DOM when the attribute value is changed
        scope.$watch(attrs.graphCanvasRefresh, function(value) {
            refreshDOM();
        });
    
        // Clean the DOM on destroy
        scope.$on('$destroy', function() {
            elem.html('');
        });
    };
    
    return  {
        link: link
    };
    }]);
    

    Dirty as hell, but this is a working solution you can use waiting for Chart.js update. Hope it can help someone.