Taylor Hill Taylor Hill - 5 months ago 185
AngularJS Question

Angular Charts.js: Can't refresh chart with data

I am new to charts/angular, and it's been a long time since I used javascript. I'm trying to use a factory in Angular to grab data from a server and use it to populate a chart (which uses Angular Charts, a wrapper around Charts.js). I can populate it originally with fake data, but changing it at all causes the chart to go blank. Do I have some sort of scoping issue here? Here's the relevant code:

.controller("LineCtrl", ["$scope", "HRDataPointFactory", function ($scope, HRDataPointFactory) {

//The following lines cause the chart to populate, but obviously I dont care about this fake data.
//$scope.labels = ["January", "February", "March", "April", "May", "June", "July"];
//$scope.series = ["Series A", "Series B"];
//$scope.data = [
// [65, 59, 80, 81, 56, 55, 40],
// [28, 48, 40, 19, 86, 27, 90]
//];
$scope.onClick = function(points, evt) {
console.log(points, evt);
};


$scope.data = [[]];
$scope.labels = [];
$scope.series = ["Department"];

$scope.getData = function() {
HRDataPointFactory.getData($scope.department, $scope.dt1, $scope.dt2)
.then(function (data) {

var i;
for (i = 0; i < data.data.length; i++) {
$scope.data[0].push(data.data[i].EmployeeCount);
}

for (i = 0; i < data.data.length; i++) {
$scope.labels.push(data.data[i].Date);
}

});
}

/*unrelated stuff here*/
}
])
.factory("HRDataPointFactory", function HRDataPointFactory($http) {
var exports = {};

exports.getData = function(deptKey, start, end) {
var config = {
params: { departmentKey: deptKey, startTime: start, endTime: end }
}

return $http.get("/HR/Data", config)
.then(function(response) {
console.log(response);
return response;
},function(data) {
console.log("There was an error!", data);
return response;
});
};

return exports;
});


And the html:

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


Thank you for the help!

Answer

I created a Plunker with a working example. To simplify I only pull the data (not the labels, etc.), but that is easy to complete.

In the controller, we assign vm to this and in the function getData I reference vm.data. Before you had $scope which is a different $scope in the function that the one you assign as a blank array.

    .controller('MyCtrl', ['$scope', 'HRDataPointFactory', function($scope, HRDataPointFactory) {
      var vm = this;
      //The following lines cause the chart to populate, but obviously I dont care about this fake data.
      vm.labels = ["January", "February", "March", "April", "May", "June", "July"];
      vm.series = ["Series A", "Series B"];
//      vm.data = [
//        [65, 59, 80, 81, 56, 55, 40],
//        [28, 48, 40, 19, 86, 27, 90]
//      ];
      vm.onClick = function(points, evt) {
        console.log(points, evt);
      };

      vm.data = [
        []
      ];
      vm.getData = function() {
        HRDataPointFactory.getData($scope.department, $scope.dt1, $scope.dt2)
          .then(function(success) {
            console.log(JSON.stringify(success));
            vm.data = success.data;

          });
      }
      vm.getData();

      /*unrelated stuff here*/
    }])

I print in the console the data I receive:

{"data":[[65,59,80,81,56,55,40],[28,48,40,19,86,27,90]],"status":200,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"params":{},"url":"data","headers":{"Accept":"application/json, text/plain, */*"}},"statusText":""}

The data is hosted on plunker too using this as a format:

[
    [65, 59, 80, 81, 56, 55, 40],
    [28, 48, 40, 19, 86, 27, 90]
]

Please not that I also used the "Controller as" syntax in the HTML to respect best practices... see john papa's article on this subject.

 <div ng-controller="MyCtrl as vm">
<canvas id="line" class="chart chart-line" chart-data="vm.data"
        chart-labels="vm.labels" chart-legend="true" chart-series="vm.series"
        chart-click="onClick">
</canvas>

  </div>

Let us know.