Reputation: 9990
This is how I have my JS set up:
Basically I have a page, and on that page there is a chart. I want to have a loading spinner show while the chart data is loading.
angular.module('myApp', [])
.service('chartService', ['$http', function($http) {
var svc = {};
svc.updateChartData = function($scope) {
$scope.loading = true;
$http({method: 'GET', url: 'http://example.com/getjson'})
.success(function(response) {
var data = google.visualization.arrayToDataTable(JSON.parse(response));
var options = {
...
};
var chart = new google.visualization.ComboChart(document.getElementById('chart_div'));
chart.draw(data, options);
$scope.loading = false;
});
}
return svc;
}])
.controller('PageController', ['$scope', '$http', 'chartService', function($scope, $http, chartService) {
$scope.loading = true;
// When select option changes
$scope.updateData = function() {
chartService.updateChartData($scope);
};
}])
.controller('ChartController', ['$scope', '$http', 'chartService', function($scope, $http, chartService) {
// On load
chartService.updateChartData($scope);
}]);
I am using ng-hide="loading"
and `ng-show="loading" to make sure the spinner and the chart show at the correct times.
However, I've noticed that the call below // On load
- doesn't actually turn the loading
to false. Another message on SO suggested there is a better way to achieve this than by passing $scope
around so any suggestions would be appreciated. Thank you.
Upvotes: 0
Views: 92
Reputation: 26
first,you have two controllers,I'm assuming they are nested relations. PageController include ChartController. you want to change the value of the parent controller in the child controller. You must use a reference type rather than a value type.
$scope.loading =true;
change to
$scope.loading ={status:true};
and if you want to set false,Should be
$scope.loading.status =false;
NOT
$scope.loading ={status:false};
second, you can pass a callback function to service. like this
svc.updateChartData = function(callback) {
....
.success(){
callback();
}
}
controller code change to
.controller('ChartController', ['$scope', '$http', 'chartService',
function($scope, $http, chartService) {
// On load
chartService.updateChartData(function(){
$scope.loading =true;
});
}]);
Upvotes: 0
Reputation: 13997
It is not a good practice to pass your scope object to a service, a service is meant to be stateless. Instead utilize the callbacks of the $http
:
chartService.updateChartData().finally(function(){
$scope.loading = false;
});
And, as Grundy mentioned below, return your $http
from your service to enable callbacks:
svc.updateChartData = function($scope) {
return $http({ //.. the options });
}
I see some more bad practices though. You shouldn't add the data to your DOM from your service, instead utilize also for this the callbacks:
svc.updateChartData = function($scope) {
return $http({method: 'GET', url: 'http://example.com/getjson'});
}
controller:
// When select option changes
$scope.updateData = function() {
chartService.updateChartData().then(function(data) {
// success
// do something with the return data from the http call
}, function (error) {
// error
// handle error
}).finally (function() {
// always
$scope.loading = false;
});
};
For your google chart it would make most sense to create a directive.
Upvotes: 1