1

Is it possible to dynamically create a chart while still have a data binding to the scope?

I have the following code

<!DOCTYPE html>    
<head>
    <script src='Chart.js'></script>
    <script src='angular.js'></script>
    <script src='angular-chart.js'></script>
</head>

<body ng-app="app" ng-controller="BarCtrl">
    <h1>Chart Test</h1>
    <canvas id="myChart"> chart-series="series" </canvas>
    <script type="text/javascript">
    angular.module("app", ["chart.js"])
    .controller("BarCtrl", function($scope, $timeout) {
        $scope.labels = ['2006', '2007', '2008', '2009', '2010', '2011', '2012'];
        $scope.data = [65, 59, 80, 81, 56, 55, 40];

        var ctx = document.getElementById("myChart");
        var myChart = new Chart(ctx, {
            type: 'bar',
            data: {
                labels: $scope.labels, //should be a reference
                datasets: [{
                    data: $scope.data //should be a reference
                }]
            }
        });

        $timeout(function() {
            console.log("Time out now");
            $scope.data = [28, 48, 40, 19, 86, 27, 90];
        }, 3000);
    });
    </script>
</body>

</html>

This obviously does not update the chart after the timeout. How would I have to create this chart instead when the template variant

<canvas class="chart chart-line" chart-data="data" chart-labels="labels"
        chart-series="series" chart-click="onClick"></canvas>

is not an option because configuration changes dynamically?

2
  • try $scope.$apply() in your timeout function Commented Sep 14, 2016 at 11:17
  • Take a look at custom directives in AngularJS. Commented Sep 14, 2016 at 11:21

2 Answers 2

1

You are just updating the data but the chart has been already rendered on your view.So you need to draw it again with updated data. You can make a function to draw chart like this

function drawChart(element,dataset){
  var myChart = new Chart(element,{type:'bar',data:{labels:$scope.labels,datasets :dataset}})
}

and call it when your dataset get chanegd

Sign up to request clarification or add additional context in comments.

2 Comments

This does not solve my problem, sorry for accepting. Is it possible to create the chart dynamically so that I can still use the regular data binding? Otherwise I would now have to react to every data change myself. Instead I only want to react to config changes (say background color)
As chart rendering is in javascript that is out of angular js scope. so you need to use $apply() to make changes on view. Better you can make directive for this
0

One option is to rebuild the chart when the data changes by using the $watch option of angular.

Close to the above example would be

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <title>Chart.js demo</title>
    <script src='Chart.js'></script>
    <script src='angular.js'></script>
    <script src='angular-chart.js'></script>
</head>

<body ng-app="app" ng-controller="Ctrl">
    <textarea ng-model="chart"></textarea>
    <button ng-click="updateConfig();">Update</button>
    <canvas id="myChart"></canvas>
    <script type="text/javascript">

    getSample = function(n) {
        var res = [];
        for (var i = 0; i < n; i++) {
            res.push(Math.round(Math.random() * 100));
        }
        return res;
    }

    var app = angular.module('app', ["chart.js"]);
    app.controller("Ctrl", function Ctrl($scope, $interval) {

        $scope.chart = '{"type": "line"}';
        $scope.labels = ['2006', '2007', '2008', '2009', '2010', '2011', '2012'];
        $scope.data = getSample(7);

        $scope.updateConfig = function(testFunction) {
            var ctx = document.getElementById("myChart");
            var config = JSON.parse($scope.chart);
            config["data"] = {
                labels: $scope.labels, //should be a reference
                datasets: [{
                    data: $scope.data //should be a reference 
                }]
            }
            var myChart = new Chart(ctx, config);
        };

        $scope.$watch('data', function(){
            var ctx = document.getElementById("myChart");
            var config = JSON.parse($scope.chart);
            config["data"] = {
                labels: $scope.labels, //should be a reference
                datasets: [{
                    data: $scope.data //should be a reference 
                }]
            }
            var myChart = new Chart(ctx, config);
        }, false);

        $interval(function() {
            $scope.data = getSample(7);
            console.log("Changed data to " + $scope.data);
        }, 3000);
    });
    </script>
</body>

</html>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.