I have a straightforward form where the user selects a start date and an end date. Once these dates are selected, the tool automatically fetches data from a website in JSON format.
Below is the code for my Angular controller:
(function () {
angular.module("app-machines", ['ngFlatDatepicker'])
.factory('MachinesService', ['$http', MachinesService])
.controller('mainController', ['$scope', 'MachinesService', mainController]);
function mainController($scope, MachinesService) {
$scope.datepickerConfig_From = {
allowFuture: true,
dateFormat: 'DD.MM.YYYY',
minDate: moment.utc('2015-09-13'),
maxDate: moment.utc('2015-09-17')
};
$scope.datepickerConfig_To = {
allowFuture: true,
dateFormat: 'DD.MM.YYYY',
minDate: moment.utc('2015-09-13'),
maxDate: moment.utc('2015-09-17')
};
$scope.date_from = "14.09.2015";
$scope.date_to = "15.09.2015";
$scope.machines = [];
$scope.errorMessage = "";
$scope.change = function () {
MachinesService.getMachines($scope.date_from, $scope.date_to).then(function (response) {
angular.copy(response.data, $scope.machines);
}, function (error) {
$scope.errorMessage = "Failed to load data:" + error;
});
};
$scope.change();
}
In my getMachines
function, I make a simple GET request like this example:
return $http.get("/api/machine/2015-09-14_2015-09-16");
The JSON returned is an array of objects with the following structure for reference:
- Machine Name
- Categories (under specific machine)
- Days (each category contains a collection of days with data)
- Categories (under specific machine)
I can fetch the data successfully now thanks to your help. My next step is to display a chart for each returned machine on the page. The HTML snippet below demonstrates how I'm attempting to do it:
<div class="col-md-12" ng-repeat="machine in machines">
<h1> {{ machine.name }}</h1>
<div class="col-md-6" ng-repeat="category in machine.categories">
<h3> {{ category.name }}</h3>
<div class="col-md-6" ng-repeat="day in category.days">
<p>{{day.date | date : 'dd.MM' }}</p>
</div>
</div>
</div>
Instead of displaying categories with days, I aim to insert a bar chart with the data. To achieve this, I found ChartJs which allows me to create such charts. Below is an example script displaying a chart on the page:
var data = {..chart data};
var options = {...chart options};
var ctx = document.getElementById("myChart");
var myBarChart = new Chart(ctx, {
type: 'bar',
data: data,
options: options
});
This works well for one chart since it targets the context specified with
document.getElementById("myChart")
. The problem arises when trying to dynamically create multiple charts based on the fetched data. How can I modify my code to create individual charts for each machine?
Any guidance or code samples would be greatly appreciated as I am relatively new to AngularJS!
EDIT:
To address this issue, I updated my HTML code as follows:
<div class="col-md-12" ng-repeat="machine in machines">
<h1> {{ machine.name }}</h1>
<canvas id="{{'myChart_' + $index}}" width="400" height="400"></canvas>
</div>
This adjustment allowed me to name the charts accordingly. In my controller, I made the following changes:
$scope.change = function () {
MachinesService.getMachines($scope.date_from, $scope.date_to).then(function (response) {
//$scope.machines = response.data;
angular.copy(response.data, $scope.machines);
}, function (error) {
$scope.errorMessage = "Failed to load data:" + error;
}).finally(function () {
var data = {..same as above};
var options = {...same as above};
//assign values to the respective charts
for (var i = 0; i < $scope.machines.length -1; i++) {
var ctx = document.getElementById("myChart_" + i);
var myBarChart = new Chart(ctx, {
type: 'bar',
data: data,
options: options
});
}
});
};
The challenge I faced here was that the charts were being rendered after the execution of my code. It seemed like I was trying to access the charts before they were created by Angular on the page. I attempted to use .finally
but it did not resolve the issue.
Is there a specific technique or code snippet that I should implement for this solution to work?
EDIT2
I also tried adding the $timeout
parameter to the controller like this:
.controller('mainController', ['$scope', 'MachinesService', '$timeout', mainController]);
I then defined an external function within the controller as follows:
var changeValues = function () {
var data = {...same as before};
var options = {...same as before};
for (var i = 0; i < $scope.machines.length - 1; i++) {
var ctx = document.getElementById("myChart_" + i);
var myBarChart = new Chart(ctx, {
type: 'bar',
data: data,
options: options
});
}
};
Within the .finally
clause, I called the function using $timeout(changeValues, 0);
but the issue persisted. I seem to be missing something crucial. Any insights into what might be causing this problem?
FINAL:
Here's the final edit to my code:
angular.module("app-machines", ['ngFlatDatepicker'])
.factory('MachinesService', ['$http', MachinesService])
.controller('mainController', ['$scope', 'MachinesService', '$timeout', mainController])
.directive('onFinishRender', function ($timeout)
{
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit('ngRepeatFinished');
});
}
}
}
});