Search code examples
javascriptangularjschart.jsangular-chartist.js

Create a chart on a dynamically created canvas in Angular-chart.js


I have a div that will need to host a chart or table depending on an XHR response. In the chart case, I need the div contents to be replaced by a canvas element that chart.js uses to display a graph.

If I add the canvas element to the HTML code, angular-chart.js renders a graph. However, If I inject the canvas into a div using javascript, the canvas element will be in the dom but the chart will not be displayed.

How do I work around this?

HTML

<div ng-controller="ChartCtrl">
  <div>
    {{chart.name}}
    This works (doughnut):
    <canvas id="chart-{{$index}}" class="chart chart-doughnut" chart-data="chart.data" chart-labels="chart.labels"></canvas>
  </div>
  This Doesn't work ({{chart.type}}):
  <div id="chartDiv"> </div>
</div>

Javascript

var myApp = angular.module('myApp', ['chart.js']);

// Create the controller, the 'ToddlerCtrl' parameter 
// must match an ng-controller directive
myApp.controller('ChartCtrl', function ($scope) {
   var chart_div = $('#chartDiv');
   chart_div.empty();
   canvas_html = '<canvas id="chart-2" class="chart chart-doughnut" chart-data="chart.data" chart-labels="chart.labels"></canvas>';
   console.log(canvas_html)
   chart_div.append(canvas_html);
   //console.log(chart_div)
  $scope.chart =    {
     name: 'Chart 1',
     type: 'Doughnut',
     labels: ['EVSC', 'ISB'],
     data: [13, 44]
   };
});

Plunker Example: http://plnkr.co/edit/9JkANojIl8EXRj3hJNVH?p=preview


Solution

  • You're altering the structure of the DOM, you can't append your newly created element like that in a "vanilla" or "jQuery" way.

    You need to compile your HTML string or DOM element into a template to produce a template function that will be linked to the scope. The process will walk the DOM tree and match DOM elements to directives.

    // Instantiate the app, the 'myApp' parameter must match what is in ng-app
    var myApp = angular.module('myApp', ['chart.js']);
    
    // Create the controller, the 'ToddlerCtrl' parameter must match an ng-controller directive
    myApp.controller('ChartCtrl', function ($scope, $compile) {
      canvas_html = '<canvas id="chart-2" class="chart chart-doughnut" chart-data="chart.data" chart-labels="chart.labels"></canvas>';
    
      var element = angular.element(canvas_html);
      $compile(element)($scope);
      angular.element('#chartDiv').append(element);
    
      $scope.chart =    {
         name: 'Chart 1',
         type: 'Doughnut',
         labels: ['EVSC', 'ISB'],
         data: [13, 44]
       };
    });
    

    You can check out the result in this Plunker example.