2016-07-19 13 views
1

Ich habe eine div, die abhängig von einer XHR-Antwort ein Diagramm oder eine Tabelle hosten muss. Im Chartfall muss der div-Inhalt durch ein canvas-Element ersetzt werden, das chart.js zum Anzeigen eines Graphen verwendet.Erstellen Sie ein Diagramm auf einer dynamisch erstellten Zeichenfläche in Angular-chart.js

Wenn ich das canvas-Element zum HTML-Code hinzufüge, rendert angle-chart.js ein Diagramm. Wenn ich die Zeichenfläche jedoch mithilfe von JavaScript in ein div-Objekt einfüge, befindet sich das Element canvas im Dom, aber das Diagramm wird nicht angezeigt.

Wie kann ich das umgehen?

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 Beispiel: http://plnkr.co/edit/9JkANojIl8EXRj3hJNVH?p=preview

Antwort

1

Sie die Struktur der DOM zu verändern, können Sie Ihre neu erstellte nicht anhängen Element wie das in einer "Vanille" oder "jQuery" Weise.

Sie müssen compile Ihre HTML-Zeichenfolge oder DOM-Element in eine Vorlage, um eine Vorlagefunktion zu erzeugen, die mit der scope verknüpft werden. Der Prozess wird die DOM-Struktur durchlaufen und DOM-Elemente mit directives übereinstimmen.

// 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] 
    }; 
}); 

Sie können das Ergebnis in this Plunker example überprüfen.

+0

Super! Ich muss das verdauen. Danke für die schnelle Antwort! – Lmwangi

1

@ HiDeo's Antwort ist genau richtig, aber hier ist eine vereinfachte Richtlinie, um das gleiche zu tun (beachte die $compile immer noch). Die chartData Variable, die an die scope angehängt ist, ist die Voreinstellungen für Chartjs Charts, jeder wird funktionieren - das einzige Bemerkenswerte ist die $watch, die ich der update Eigenschaft hinzugefügt habe: Wenn Sie Ihre Diagramme aktualisieren, würde ich vorschlagen, etwas zu tun so, nur um deine Hände sauber zu halten.

.directive('replaceWithChart',function($compile){ 
    return { 
     restrict: 'A', 
     scope: { 
      chartData: '=replaceWithChart', 
      height: '=', 
      width: '=' 
     }, 
     compile: function(element){ 
      var canvasModel = angular.element('<canvas></canvas>'); 
      return { 
       post: function postLink(scope,elem,attr){ 
        elem.empty(); 
        var canvas = canvasModel.clone(); 
        elem.append($compile(canvas)(scope)); 

        !scope.height && (scope.height = elem[0].style.height || (elem[0].offsetHeight || elem[0].clientHeight)); 
        !scope.width && (scope.width = elem[0].style.width || (elem[0].offsetWidth || elem[0].clientWidth)); 

        var chart = new Chart(canvas[0].getContext('2d'),scope.chartData); 
        canvas.attr('height',(canvas[0].style.height = scope.height + 'px')); 
        canvas.attr('width',(canvas[0].style.width = scope.width + 'px')); 

        scope.$watch('chartData.update',function(){ 
         scope.chartData.update && !(scope.chartData.update = false) && chart.update(); 
        }); 
        elem.on('$destroy',chart.destroy.bind(chart)); 
        // Fixed some rendering issue, but I can't remember which 
        window.setTimeout(function(){ 
         var padding = elem[0].style.padding || (window.getComputedStyle(elem[0],null).getPropertyValue('padding')); 
         elem[0].style.padding = '0'; 
         elem[0].style.padding = padding; 
         chart.resize(); 
        },300); // Magic number - I found this worked best 
       } 
      }; 
     } 
    }; 
})