How can one pass values from services to controllers? I have been reading stackoverflow questions regarding this and none of the solutions seem to solve my problem. I am trying to access google spreadsheets using tabletop.js When I console.log from services I can see the values however when I try to access the spreadsheet values from controller I get the following error: chartService.getProperty is not a function
The code for getting URL of the spreadsheet works fine. With get method. Not sure what I am doing wrong here.
Controller
angular.module('myapp')
.controller('piechartCtrl', function (chartService, $scope, config) {
$scope.values = chartService.getProperty();
});
Service.js
angular.module('myapp')
.service('chartService', function(){
return {
getUrl: function init(path) {
Tabletop.init( { key: path,
callback: showInfo,
simpleSheet: true } )
}
}
function showInfo(data, tabletop) {
return{
getProperty: function(){
return data
},
setProperty: function(value){
data = value;
}
}
}
});
This is your service, the only thing i see you returning is the getUrl. so the only thing you will be able to access from the controller is chartService.getUrl function.
service('chartService', function ()
{
return
{
getUrl: function init(path)
{
Tabletop.init({
key: path,
callback: showInfo,
simpleSheet: true
})
}
}
function showInfo(data, tabletop)
{
return
{
getProperty: function ()
{
return data
},
setProperty: function (value)
{
data = value;
}
}
}
});
To Get it working, while I don't think this is the ideal solution it should work...
service('chartService', function ()
{
var returnObject =
{
getUrl: function init(path)
{
Tabletop.init({
key: path,
callback: showInfo,
simpleSheet: true
})
},
resultValue: {}
}
function showInfo(data, tabletop)
{
return
{
getProperty: function ()
{
return data
},
setProperty: function (value)
{
data = value;
returnObject.resultValue = value;
}
}
}
return returnObject
});
then replace chartService.getProperty() with chartService.resultValue although this is in no was synchronous.
Related
I created a controller inside a state. We usually use this kind of notation for our angular (1.5) components and services with an angular.extend(self, {}).
My problem here is when self.criteria is being initialized, the browser call self.getAgencies() and return an exception :
Error: self.getAgencies is not a function
(function (app) {
'use strict';
app.config(function ($stateProvider) {
$stateProvider.state('app.invoice', {
url: '/invoice'
abstract: true,
template: '<ui-view></ui-view>'
})
.state('app.invoice.list', {
url: '/list?allMyParam',
template: '<invoices criteria="$ctrl.criteria"></invoices>',
controllerAs: '$ctrl',
controller: function ($location) {
var self = this;
angular.extend(self,{
criteria: {
agencies: self.getAgencies()
},
getAgencies: function () {
if ($location.search().agencies) {
return undefined;
} else {
return ['foo', 'blah'];
}
}
});
}
});
});
})(angular.module('module', []));
I put getAgencies() function over the criteria prototype initialization but it did not change anything.
I got out of it by moving getAgencies() outside of angular.extend(self, {}) like this :
var self = this;
var getAgencies = function () {
if ($location.search().agencies) {
return undefined;
} else {
return ['foo', 'blah'];
}
}
angular.extend(self, {
criteria: {
agencies: getAgencies()
}
});
My code is working so it is ok for me but I would like to understand why my self.getAgencies() is not working when this call inside a controller component works well, and make it better if I can.
I'm using angular-ui-router 0.2.18 with angular 1.5.0.
Thank you for your help.
Because when this code is reached
criteria: {
agencies: self.getAgencies()
},
the angular.extend function has not been called yet, and there is no reason why self should contain the getAgencies function.
Why not initialize the agencies afterwards?
angular.extend(self,{
criteria: { },
getAgencies: function () {
if ($location.search().agencies) {
return undefined;
} else {
return ['foo', 'blah'];
}
}
});
self.criteria.agencies = self.getAgencies();
Alternatively, you could use a getter and post-pone calling the function:
angular.extend(self,{
criteria: {
get agencies() {
if (!self._agencies) {
self._agencies = self.getAgencies();
}
return self._agencies;
}
},
getAgencies: ...
});
How can I access values returned from service using controller. In my code service.js function showInfo() returns JSON objects. But I cannot access these objects outside this function. If I try to do console.log from controller.js
console.log(chartService.showInfo.new_data)
I get
error Cannot read property 'new_data' of undefined.
Same happens if I try to
console.log(chartService.showInfo)
I get undefined.
How can I access the JSON object new_data inside function showInfo from the controller?
Service.js
angular.module('myApp')
.service('chartService', function (){
return {
getUrl: function init(path) {
Tabletop.init( { key: path,
callback: showInfo,
simpleSheet: true } )
}
}
function showInfo(data, tabletop){
var new_data = JSON.stringify(data.map(function(el) {
return {
"name": el[Object.keys(el)[0]],
"y": +el[Object.keys(el)[1]]
};
}));
}
})
Controller.js
angular.module('myApp')
.controller('piechartCtrl', [ '$scope', 'chartService', function (chartService, $scope) {
console.log(chartService.showInfo.new_data)
}]);
Service
angular.module('myApp').service('chartService', function (){
return {
init: init,
showInfo: showInfo
};
function init(path) {
return Tabletop.init({
key: path,
callback: showInfo,
simpleSheet: true
});
}
function showInfo(data, tabletop){
return JSON.stringify(data.map(function(el) {
return {
"name": el[Object.keys(el)[0]],
"y": +el[Object.keys(el)[1]]
};
}));
}
});
Controller
angular.module('myApp').controller('piechartCtrl', [ '$scope', 'chartService', function (chartService, $scope) {
var tabletop = chartService.init(),
chartInfo = chartService.showInfo(someData, tabletop);
console.log(chartInfo);
}]);
I don't know exactly what you wanted with the parameters in showInfo but this should get you a good way in the right direction.
Best way is with Promise.
In angular you have the q framework as $q service $q docs
Service
angular.module('myApp')
.service('chartService', function($q) {
var deferredSpreadsheet = $q.defer();
return {
getSpreadsheet: function init(path) {
Tabletop.init({
key: path,
callback: showInfo,
simpleSheet: true
});
return deferredSpreadsheet.promise;
},
}
function showInfo(data, tabletop) {
data = JSON.stringify(data.map(function(el) {
return {
"name": el[Object.keys(el)[0]],
"y": el[Object.keys(el)[1]]
};
}));
deferredSpreadsheet.resolve(data);
}
})
Controller
angular.module('myApp')
.controller('piechartCtrl', ['$scope', 'chartService', function($scope, chartService) {
var path = "https://docs.google.com/spreadsheet/pub?hl=en_US&hl=en_US&key=0AmYzu_s7QHsmdDNZUzRlYldnWTZCLXdrMXlYQzVxSFE&output=html";
var pro = chartService.getSpreadsheet(path).then(function(data) {
console.log(data)
})
}]);
Working example here
Dirty way: You can use Broadcast and Emit
in the Service:
$rootScope.$broadcast('myEvent', JSONSTUFF);
in the Controller:
$scope.$on("myEvent", function(e, json){
console.log(json);
});
I am trying to assign a variable from $http.get() though the conf var is null despite the request going through and returning json.
app.factory('Config', ['$http',
function($http) {
return {
conf: null,
init: function () {
if (this.conf === null) {
$http.get('/config')
.success(function (data) {
this.conf = data;
});
}
}
}
}
]);
this inside success callback function is different
app.factory('Config', ['$http',
function($http) {
return {
conf: null,
init: function () {
var self = this;
if (this.conf === null) {
$http.get('/config')
.success(function (data) {
self.conf = data;
});
}
}
}
}
]);
Im just starting on AngularJS. I'm not sure how to churn this out. I'm trying to include multiple functions within one service. (I hope this is not against bad practice.)
The following is my working code:
myDataService.async().then(function (d) {
$scope.dbCalls = d.d;
});
My Service:
app.factory('myDataService', function ($http) {
// How do you get this bottom line to work?
// this.getAllCalls = function () {
var myService = {
async: function () {
var promise = $http.post('AngularTest.aspx/FetchCalls', { data: {} }).then(function (response) {
console.log(response);
return response.data;
});
return promise;
}
};
return myService;
//}; <--Commented out for clarity
});
Thanks!
you just return an object with properties from the service, then you are able to call those properties as different service methods
like so:
.service('myService', function() {
return {
firstMethod: function() { ... },
secondMethod: function() { ... },
thirdMethod: function() { ... }
}
})
and in the controller/directive
.controller('myCtrl', function(myService) {
myService.firstMethod();
myService.secondMethod();
myService.thirdMethod();
})
I am trying to listen to changes in my injected service (self-updating) in the controller. In the below example you'll find two $watch cases - one that works but I don't know exactly why and one that was obvious to me, yet doesn't work. Is the second example the right way to do it? Isn't that code duplication? What is the right way to do it?
Service:
app.factory("StatsService", [
'$timeout', 'MockDataService',
function ($timeout, MockDataService) {
var service, timeout;
timeout = 5000;
service = {
fetch: function () {
// Getting sample data, irrelevant, however this is what updates the data
return this.data = MockDataService.shuffle();
},
grab: function () {
this.fetch();
return this.update();
},
update: function () {
var _this = this;
return $timeout(function () {
return _this.grab();
}, timeout);
}
};
service.grab();
return service;
}
]);
Controller:
app.controller("StatsController", [
'$scope', 'StatsService',
function ($scope, StatsService) {
var chart;
$scope.stats = StatsService;
$scope.test = function (newValue) {
if (arguments.length === 0) {
return StatsService.data;
}
return StatsService.data = newValue;
};
// This doesn't work
$scope.$watch('stats', function (stats) {
return console.log('meh');
});
// This works, don't know why
$scope.$watch('test()', function (stats) {
return console.log('changed');
});
}
]);
See the third parameter for $watch: objectEquality
Compare object for equality rather than for reference.
However if you're only interested in watching the returned data, then you should do:
$scope.$watch('stats.data', function (stats) {
return console.log('meh');
});
You could use $rootScope events. For example inside the service you could dispatch an event with $rootScope.$broadcast("somethingFetched", data) and catch it in the controller $scope.$on("somethingFetched", function(event, data) { $scope.data = data }).
More details you could find in the documentation http://docs.angularjs.org/api/ng.$rootScope.Scope