我有一个简单的表单,用户选择日期和日期,然后工具自动从网站检索数据(它返回一个JSON)。
以下是我的角度控制器的样子:
(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();
}
我的getMachines
中我在调用一个看起来或多或少像这样的简单GET请求(示例):
return $http.get("/api/machine/2015-09-14_2015-09-16");
返回的JSON是具有以下结构的对象数组(仅供参考)
我现在可以毫无问题地检索数据(得到了大家的帮助)。我现在正在尝试为每台退回的机器显示一个图表。这意味着在我的页面上我试图做这样的事情:
<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>
这里(只是简单的例子)我在循环机器,我正在显示类别与天。我不想显示类别(天数),而只想插入带有数据的条形图。
我发现ChartJs允许我这样做。这是我的示例脚本,它在我的页面上显示一个图表:
var data = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
label: "My First dataset",
// The properties below allow an array to be specified to change the value of the item at the given index
// String or array - the bar color
backgroundColor: "rgba(100,220,220,0.2)",
// String or array - bar stroke color
borderColor: "rgba(220,220,220,1)",
// Number or array - bar border width
borderWidth: 1,
// String or array - fill color when hovered
hoverBackgroundColor: "rgba(220,220,220,0.2)",
// String or array - border color when hovered
hoverBorderColor: "rgba(220,220,220,1)",
// The actual data
data: [65, 59, 80, 81, 56, 55, 40],
// String - If specified, binds the dataset to a certain y-axis. If not specified, the first y-axis is used.
yAxisID: "y-axis-0",
},
{
label: "My Second dataset",
backgroundColor: "rgba(220,220,220,0.2)",
borderColor: "rgba(220,220,220,1)",
borderWidth: 1,
hoverBackgroundColor: "rgba(220,220,220,0.2)",
hoverBorderColor: "rgba(220,220,220,1)",
data: [28, 48, 40, 19, 86, 27, 90]
}
]
};
var options = {
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
};
var ctx = document.getElementById("myChart");
var myBarChart = new Chart(ctx, {
type: 'bar',
data: data,
options: options
});
这就像一个魅力,但只适用于一个图表 - 因为我们使用document.getElementById("myChart")
定位上下文。
问题是 - 如何更改此设置以从我返回的数据创建图表?作为备份解决方案,我提前预先设计了页面(我知道返回的最大机器数量)并简单地隐藏那些不应该出现的页面....但我知道这不是正确的方法(它&#39 ;备用计划)。我想学习如何正确地做到这一点。
对此事的任何帮助都将不胜感激。我是一名AngularJS新手,因此您的代码示例将非常受欢迎!
修改:
根据建议,我已将HTML代码更新为以下内容:
<div class="col-md-12" ng-repeat="machine in machines">
<h1> {{ machine.name }}</h1>
<canvas id="{{'myChart_' + $index}}" width="400" height="400"></canvas>
</div>
将这些图表命名为没有问题。然后,在我的控制器下,我将代码更改为以下内容:
$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};
//now assign those values to the representative 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
});
}
});
};
我遇到的问题是,在我的代码执行后,我的图表会呈现。这意味着我尝试在我的页面上由Angular实际创建之前找到我的图表。我已尝试(如您所见)将.finally
子句添加到我的代码中,但它不起作用。
是否需要使用开关/代码才能使此解决方案正常工作?
EDIT2
我还尝试将以下参数$timeout
添加到控制器中,如下所示:
.controller('mainController', ['$scope', 'MachinesService', '$timeout', mainController]);
然后我使finally子句成为这样的外部函数(在同一个控制器内):
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
});
}
};
从finally子句中我调用了我的函数$timeout(changeValues, 0);
,但它仍然不起作用。我现在很迷茫。我错过了什么?
FINAL :
以下是我最终编辑代码的方法:
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');
});
}
}
}
});
答案 0 :(得分:2)
可能有更好的答案,但是......
您可以使用角度循环来创建初始HTML元素。
<div class="col-md-12" ng-repeat="machine in machines">
<h1> {{ machine.name }}</h1>
<canvas id="{{'myChart_' + $index}}" width="400" height="400"></canvas>
</div>
然后在你的控制器中将元素传递给DOM并$broadcast
一个事件来绘制图表。
$scope.change = function () {
MachinesService.getMachines($scope.date_from, $scope.date_to).then(function (response) {
angular.copy(response.data, $scope.machines);
$scope.$broadcast('chartReady'); //broadcast the event
}, function (error) {
$scope.errorMessage = "Failed to load data:" + error;
});
};
同样在您的控制器中处理广播事件。我从here.
借用并修改了此代码directive('drawCharts', ['$timeout', function ($timeout) {
return {
link: function ($scope, element, attrs) {
$scope.$on('chartReady', function () {
$timeout(function () { // You might need this timeout to be sure its run after DOM render.
//get chart elements and draw chart here
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
});
}
}, 0, false);
})
}
};
}]);