angularJS service object property undefined - angularjs

I have a controller using a service chartFactory.chartData property to give some data to view. The problem is that the factory is returning the object before the chartFactory.chartData function has time to return the data from the back end, so the property is undefined.
I understand this is an async issue, but I'm not sure how to handle it between a factory and a controller.
chartFactory.js
app.factory('chartFactory', ['$http', '$interval', function($http, $interval) {
var service = {
get chartData() {
$http.get('/portfolio/get-chart-data')
.then(function(response) {
console.log(response.data, 'response data') //logging after undefined message
return response.data
})
}
}
return service
}])
chartController.js
app.controller('chartCtrl', function($scope, $timeout, $http, chartFactory) {
$scope.chartData = chartFactory
$scope.height_chart = window.innerHeight * 0.4
$scope.labels = chartFactory.chartData[0]; //undefined
$scope.series = chartFactory.chartData['GDAX Value']; //undefined
$scope.data = [
chartFactory.chartData[1] //undefined
];
$scope.onClick = function(points, evt) {
console.log(points, evt);
};
$scope.datasetOverride = [{
yAxisID: 'y-axis-1'
}];
$scope.options = {
responsive: true,
maintainAspectRatio: false,
scales: {
yAxes: [{
id: 'y-axis-1',
// type: 'linear',
display: true,
position: 'left',
ticks: {
beginAtZero: false,
callback: function(value, index, values) {
if (parseInt(value) >= 1000) {
return '$' + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
} else {
return '$' + value;
}
}
}
}],
xAxes: [{
display: false
}]
}
}
})

Change your controller as,
chartFactory.chartData().then(function(response) {
$scope.labels = getchartData .response.data[0];
$scope.series = chartFactory.response.data['GDAX Value'];
});

Related

Can't empty $scope.labels and $scope.data used when drawing angular-charts

I am using angular-chart.js to draw some graphs. And I am using array values to set the values for $scope.labels and $scope.data from database. I want to make the $scope.labels and $scope.data empty after each call of the function. please find the below code
angular.module("app", ["chart.js"])
.controller("LineCtrl", function ($scope) {
$scope.labels = [];
$scope.data = [[]];
$scope.graphFunc = function(array) {
for(var i =0; i < array.length; i++)
{
$scope.labels.push(array[i].name);
$scope.data[0].push(array[i].age)
}
$scope.onClick = function (points, evt) {
console.log(points, evt);
};
$scope.datasetOverride = [{ yAxisID: 'y-axis-1' }, { yAxisID: 'y-axis-2' }];
$scope.options = {
scales: {
yAxes: [
{
id: 'y-axis-1',
type: 'linear',
display: true,
position: 'left'
},
{
id: 'y-axis-2',
type: 'linear',
display: true,
position: 'right'
}
]
}
};
};
$scope.labels = [];
$scope.data = [[]];
});
But then the graph is not appearing. Please note that my array is a dynamic and array format is as follows
var arrayVal = [{name:A,age:10},{name:B,age:30}];
UPDATED
HTML
<canvas id="line" class="chart chart-line" chart-data="data"
chart-labels="labels" chart-series="series" chart-options="options"
chart-dataset-override="datasetOverride" chart-click="onClick">
</canvas>
I could find the issue which is rather than declaring $scope.labels and $scope.data inside controller, by declaring these two global variables inside chartFunc() this issue can be overcome. Therefore you don't have to reinitialize the two variables at the end of the chartFunc().
angular.module("app", ["chart.js"])
.controller("LineCtrl", function ($scope) {
$scope.graphFunc = function(array) {
$scope.labels = [];
$scope.data = [[]];
for(var i =0; i < array.length; i++)
{
$scope.labels.push(array[i].name);
$scope.data[0].push(array[i].age)
}
$scope.onClick = function (points, evt) {
console.log(points, evt);
};
$scope.datasetOverride = [{ yAxisID: 'y-axis-1' }, { yAxisID: 'y-axis-2' }];
$scope.options = {
scales: {
yAxes: [
{
id: 'y-axis-1',
type: 'linear',
display: true,
position: 'left'
},
{
id: 'y-axis-2',
type: 'linear',
display: true,
position: 'right'
}
]
}
};
};
});
What happens is each time the user wants to see a graph the two variables are reinitialized inside the chartFunc and previous array values are removed autuomatically

Bind array to highcharts data part using Angular Directives

I need to bind an array of data to "data" part of highcharts which is embedded in
Angular directives but I don't know how exactly to do that.
This is my controller part which fetches data from repository:
vm.data = [];
function getVmAll(forceRefresh) {
return datacontext.esxservers.getAllWithoutPaging(forceRefresh, vm.vmAllSearchTemp)
.then(function (data) {
vm.data= data;
});
return data;
}
);
}
and here is the template which I use the controller in it:
<section class="mainbar" data-ng-controller="mbVirtualizationOverviewCtrl as vm">
<mb-virtualization-overview-donut-chart value="vm.data"></mb-virtualization-overview-donut-chart>
</section>
and the last but not least one is my directive which I use highcharts settings:
'use strict';
angular.module('app').directive('mbVirtualizationOverviewDonutChart', [
function () {
return {
restrict: "E",
templateUrl: '/app/directives/virtualizationOverview/mbVirtualizationOverviewDonutChartTemplate.html',
scope: {
value : "="
},
link: function (scope, el, attrs) {
scope.chart = Highcharts.chart(el[0], {
chart: {
type: 'pie',
},
title: {
text: scope.innerTitle
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: false
},
showInLegend: true
}
},
series: [{
data: undefined
}]
});
var init = true;
scope.$watch(
function () {
var chart = scope.chart;
if (init && scope.value.length > 0) {
init = false;
scope.value.forEach(function (item, index) {
chart.series[0].data.push(item);
});
}
});
}
};
}
]);

Angularjs directive scope seems not binding to value

Please spare me if this is a beginner type of question. I'm playing Highcharts.js with Angular.js, but it's seems like directive scope is not binding to value. Below are my codes.
HTML - but it's working inside this expressions {{xaxis}} {{seriesdata}}
<div class="container" ng-controller='chartController'>
<div class="row">
<div class="col-md-6">
<line-chart xaxis='xaxis' seriesdata='seriesdata'></line-chart>
{{xaxis}}
{{seriesdata}}
</div>
<div class="col-md-6">
<bar-chart options='pieOptions'></bar-chart>
</div>
</div>
</div>
directive.js
(function() {
'use strict';
angular
.module('chart')
.directive('lineChart', lineChartDirective);
/* #ngInject */
function lineChartDirective() {
return {
restrict: 'E',
replace: true,
template: '<div></div>',
scope: {
xaxis: '=xaxis',
seriesdata: '=seriesdata'
},
link: function(scope, element) {
Highcharts.chart(element[0], {
chart: {
type: 'spline',
zoomType: 'x'
},
plotOptions: {
line: {
dataLabels: {
enabled: true
}
}
},
title: {
text: 'Profit Ratio by Month'
},
xAxis: {
categories: scope.xaxis
},
yAxis: {
title: {
text: 'Profit %'
}
},
series: [
{
name: 'Total',
data: scope.seriesdata
}
]
});
}
}
}
})();
service.js
(function() {
'use strict';
angular
.module('chart')
.factory('chartData', chartDataFactory);
chartDataFactory.$inject = ['$http'];
/* #ngInject */
function chartDataFactory($http) {
function getData() {
return $http.get('../../data/sampleData.json').then(function(result) {
return result.data;
})
}
return {
getData: getData
}
}
})();
controller.js
(function() {
'use strict';
angular
.module('chart')
.controller('chartController', chartController);
chartController.$inject = ['$scope', 'chartData', 'lodash'];
/* #ngInject */
function chartController($scope, chartData, lodash) {
var vm = this;
chartData.getData().then(function(data) {
$scope.chartData = data;
$scope.xaxis = data.SEO[0]["SEO-MOD-001"]["SEO-END-001"];
$scope.seriesdata = data.SEO[0]["SEO-MOD-001"]["SEO-END-002"];
console.log($scope.xaxis);
console.log($scope.seriesdata);
});
$scope.pieOptions = {
chart: {
type: 'column'
},
title: {
text: 'Projects'
},
xAxis: {
categories: ['Noreil', 'Ken', 'Alfie', 'Francis']
},
yAxis: {
title: {
text: 'Completed Projects'
}
},
series: [
{
name: 'Quarter 1',
data: [23, 11, 34, 26]
},
{
name: 'Quarter 2',
data: [14, 20, 26, 30]
}
]
}
}
})();
When the directive link function gets executed, you don't have data yet. So try following in link function:
var unwatch = scope.$watch('[xaxis, seriesdata]', function (results) {
if (results[0] && results[1]) {
init();
unwatch();
}
}, true);
function init() {
// Highcharts.chart(element[0], { ...
}

Why isn't my spline chart showing when using combo charts?

So I'm using Highcharts-ng with Angular to create a combination chart of a spline chart and a column chart formatted as a histogram to show trends.
The way it works is that the on the load of the page, I only see the histogram, and not the spline. Changing the order does nothing.
It looks as though if I have the spline chart data hard-coded it shows, but using the program to add in the data after a service is called in does not work.
(function() {
'use strict';
angular
.module('app.widgets')
.directive('trends', trends);
trends.$inject = ['ResultsService'];
/* #ngInject */
function trends() {
var ddo = {
restrict: 'EA',
templateUrl: 'app/widgets/trends/trends.directive.html',
link: link,
scope: {
data: '=',
config: '='
},
controller: controller,
controllerAs: 'vm',
bindToController: true
};
return ddo;
function link(scope, element, attrs) {
}
function controller($scope, ResultsService) {
var vm = this;
var parent = $scope.widgetController;
var size = {
height: angular.element('li.widget-border.ng-scope.gridster-item')[1].style.height - 20 ,
width: angular.element('li.widget-border.ng-scope.gridster-item')[1].style.width - 20
};
vm.histogram = {
chart: {
zoomType: 'xy'
},
title: {
text: 'Average Monthly Weather Data for Tokyo'
},
subtitle: {
text: 'Source: WorldClimate.com'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
crosshair: true
},
yAxis: { // Primary yAxis
labels: {
style: {
color: Highcharts.getOptions().colors[2]
}
},
title: {
text: 'Events',
style: {
color: Highcharts.getOptions().colors[2]
}
}
},
tooltip: {
shared: true
},
legend: {
layout: 'vertical',
align: 'left',
x: 80,
verticalAlign: 'top',
y: 55,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'
},
series: [{
name: 'Average',
type: 'spline',
data: [],
marker: {
enabled: true
}
}],
loading: false,
useHighStocks: false,
size: {
height: size.height,
width: size.width
}
};
vm.processChartData = processChartData;
vm.data = {
charts: {
}
};
ResultsService.getData().then(function(res) {
vm.data = {
charts: {}
};
vm.data.charts = processChartData(res);
vm.histogram.xAxis.categories = [];
vm.histogram.series.push ({
name: 'Events per month',
type: 'column',
data: [],
marker: {
enabled: true
}
});
console.log(vm.histogram.series);
angular.forEach(vm.data.charts.months, function(v,k){
vm.histogram.xAxis.categories.push(k);
vm.histogram.series[1].data.push(v);
});
vm.histogram.options = {
plotOptions: {
}
};
vm.histogram.options.plotOptions = {
column: {
borderWidth: 0.5,
groupPadding: 0,
shadow: true
},
};
console.log(vm.data.charts.months);
vm.histogram.xAxis.categories.sort();
var average = calculateAverage();
vm.histogram.series[0].data=average;
console.log(vm.histogram.series);
});
function swap(pos1, pos2){
var temp = vm.histogram.series[pos1];
vm.histogram.series[pos1] = vm.histogram.series[pos2];
vm.histogram.series[pos2] = temp;
}
function calculateAverage() {
var averageArray = [];
var total = 0;
angular.forEach(vm.data.charts.months, function(v,k){
console.log(v);
total += v;
});
console.log((total/12.0).toFixed(2));
var average = (total/12.0).toFixed(2);
angular.forEach(vm.histogram.xAxis.categories, function(v,k){
averageArray.push(average);
});
return averageArray;
}
function processChartData(data) {
var output = {};
var months = {};
var dayOfWeek = {};
var epoch = {};
angular.forEach(data, function (value, index) {
// by month
if (!months[value.eventDate.month]) {
months[value.eventDate.month] = 1;
}
months[value.eventDate.month] += 1;
// by day of week
if (!dayOfWeek[value.eventDate.dayOfWeek]) {
dayOfWeek[value.eventDate.dayOfWeek] = 1;
}
dayOfWeek[value.eventDate.dayOfWeek] += 1;
// by day
if (!epoch[value.eventDate.epoch]) {
epoch[value.eventDate.epoch] = 1;
}
epoch[value.eventDate.epoch] += 1;
});
output.months = months;
output.dayOfWeek = dayOfWeek;
return output;
}
$scope.$on('gridster-item-resized', function(item){
var element = angular.element(item.targetScope.gridsterItem.$element[0]);
vm.histogram.size = {
height: element.height()-35,
width: element.width()
};
$scope.$broadcast('highchartsng.reflow');
});
}
}
})();
The chart on the webpage looks like this with the given code!
As you can see, it shows the legend with the spline, but the spline doesn't show up. I can't figure out why.
Your calculateAverage() function returns an array of strings since .toFixed(2) returns a string. Make sure it's an array of numbers. Convert average to a number with average = parseFloat(average) for example.

Update $scope with $resource

Why is only the one that don't use $resource.get() work? I am using kendo-angular to update. Has this something to do with async? The main variable looks exactly the same so this has to have something to do with $resourse. What am I missing`
This works:
app.controller('SubjectCntrl', ['$scope', 'categoryService', function($scope, categoryService) {
var main = categoryService.getCategories();
var subjects = {
data : [main]
};
$scope.subjects = {
dataSource: subjects
};
}]);
This does not:
app.controller('SubjectCntrl', ['$scope', 'categoryService', 'ApiFactory', function($scope, categoryService, ApiFactory) {
ApiFactory.get(function(categoriesData) {
var main = categoryService.getCategories();
var subjects = {
data : [main]
};
$scope.subjects = {
dataSource: subjects
};
});
}]);
The factory:
app.factory('ApiFactory', ['$resource', function($resource) {
return $resource('http://localhost:8080/rest/forum/categories/1');
}]);
Service:
app.service('categoryService', ['$resource', function($resource){
this.getCategories = function(){
var farmingSubjects = [ {text: "Poteter", spriteCssClass: "subject"}, {text: "Agurk", spriteCssClass: "subject"} ];
var forestSubjects = [ {text: "Tall", spriteCssClass: "subject"}, {text: "Gran", spriteCssClass: "subject"} ];
var animalSubjects = [ {text: "Hundar", spriteCssClass: "subject"}, {text: "Katter", spriteCssClass: "subject"} ];
var farming = { text: "Jordbruk", items: farmingSubjects };
var forest = { text: "Skogshold", items: forestSubjects };
var animals = { text: "Dyrebruk", items: animalSubjects };
var subjects = [farming, forest, animals ];
var main = { text: "Huvudemner", expanded: true, items: subjects};
return main;
};
}]);
Edit: The success function is called without doubt.
ApiFactory.get(function(data){
console.log('success, got data: ', data);
}, function(err){
alert('request failed');
});
I think the second case is not working because you ApiFactory call is failing. The callback you have declared is for success.

Resources