Can I have multiple functions in my AngularJS Factory? - angularjs

I'm following the Tutorial from the official AngularJS docs and I want to know if I can add another function to the Phone factory so that I can organize code better. They have declared a "query" function, but what if I wanted to add a query2 function that references a different url...say phones2/:phoneName.json for example?
Factory declaration:
var phonecatServices = angular.module('phonecatServices', ['ngResource']);
phonecatServices.factory('Phone', ['$resource',
function($resource){
return $resource('phones/:phoneId.json', {}, {
query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
});
}]);
I have tried a number of things and non of them seem to be working :s
This answer seems to be on the right track, but the syntax for each factory function doesn't quite match up with the above factory.
Something along the lines of:
phonecatServices.factory('Phone', ['$resource',
function($resource){
return {
query: ...
query2: ...
}
}]);

One such example of this is:
Link for Demo
angular.module('services', []).factory('factoryName', ["$filter",
function($filter) {
var method1Logic = function(args) {
//code
};
var method2Logic = function(args) {
//code
};
return {
method1: method1Logic,
method2: method1Logic
};
}
]).controller('MainController', ["$scope", "$rootScope", "$filter", "factoryName", function ($scope, $rootScope, $filter,factoryName) {
$scope.testMethod1 = function(arg){
$scope.val1 = factoryName.method1(arg);
};
$scope.testMethod2 = function(arg){
$scope.val2 = factoryName.method2(arg);
};
}]);
There is even a better version Opinionated version of this: References
function AnotherService () {
var AnotherService = {};
AnotherService.someValue = '';
AnotherService.someMethod = function () {
};
return AnotherService;
}
angular
.module('app')
.factory('AnotherService', AnotherService);

This is the service code:
myServices.factory('Auth', ['$resource',
function($resource){
return {
Login: $resource(serviceURL + 'login', {}, { go: { method:'POST', isArray: false }}),
Logout: $resource(serviceURL + 'logout', {}, { go: { method:'POST', isArray: false }}),
Register: $resource(serviceURL + 'register', {}, { go: { method:'POST', isArray: false }}),
};
}
]);
And from my controller I just have to add the go() function call to make it work:
Auth.Login.go({ username: $scope.username, password: $scope.password },
I guess I could have named the go function after the method and called it "post()" instead for clarity...

Yes, Of course, you can have multiple functions in an object. The only caveat is your service should return an object. You can have all the valid javascript members in that object as long as you follow object's syntax.
So following is possible
phonecatServices.factory('Phone', ['$resource',
function($resource){
return {
query: ... , // NOTICE THE COMMA HERE
query2: ...
}
}]);
You must be missing the comma (,) to separate your object's key values.

Related

calling function inside angular factory

I have a factory, how do i call 'getAccountDetails' service inside getAccountInformation() function.
I tried in the following way, but not working.
AccountService.getAccountDetails.getAccountDetailsService
factory
tellerApp.factory('AccountService',['$resource', function ($resource) {
return{
getAccountDetails: $resource(XXX, {}, {
getAccountDetailsService: {}
}),
getAccountInformation: function($scope, number, transaction, index){
AccountService.getAccountDetails.getAccountDetailsService({number : number})
.$promise.then(function(response){});
}
}]);
I suggest you define your code dependencies out of the returned provider:
tellerApp.factory('AccountService',['$resource', function ($resource) {
var getAccountDetails = $resource(XXX, {}, {getAccountDetailsService: {}});
return {
getAccountDetails : getAccountDetails,
getAccountInformation: function($scope, number, transaction, index){
getAccountDetails.getAccountDetailsService({number : number}).$promise.then(function(response){
...
})
}
};
}]);
Or, inside an object, you can also use this to refer to the current object, instead of using AccountService.getAccountDetails, you should use this.getAccountDetails.
tellerApp.factory('AccountService',['$resource', function ($resource) {
return {
getAccountDetails : $resource(XXX, {}, {getAccountDetailsService: {}});,
getAccountInformation: function($scope, number, transaction, index){
this.getAccountDetails.getAccountDetailsService({number : number}).$promise.then(function(response){
...
})
}
};
}]);
Plus, be careful, because your naming convention is confusing (getAccountDetails is not a function, since you don't call it with (), but it is named "get", getAccountServices is first defined as an object, but the same name is used later for a funtion...), especially if you want an accurate answer ;)
This should work, havent tested it though.
tellerApp.factory('AccountService',['$resource', function ($resource) {
var AccountService = {
getAccountDetails: $resource(XXX, {}, {
getAccountDetailsService: {}
}),
getAccountInformation: function($scope, number, transaction, index){
AccountService.getAccountDetails.getAccountDetailsService({number : number}).$promise.then(function(response){
}
};
}
return AccountService
}]);

AngularJS hide promises while using $resource

I have a simple RESTful service like the following:
services.factory('UserService', ['$resource, function() {
return $resource('...');
}]);
This way I have to invoke like this:
UserService.get({id: userId}, function(response) {
// do something.
});
I wanted to be able to do something like this:
UserService.get(userId).then(function(response) {
// do something with data
});
Is it possible? I am struggling with this and end up always having to use $promise.then() in my controllers. I wanted to "hide" that $promise in my RESTful service.
$resource purposely exposes the promise through ... well ... $promise, so you can use the UserService to abstract this:
services.factory("UserService", ["$resource", function ($resource) {
var userService = $resource("...");
return {
get: function (id) {
return userService.get({id: id}).$promise;
}
}
});
According to Todd Motto you could encapsulate your service somewhat like this :
"We create an Object with the same name inside the function. This can aid documentation as well for comment-generated docs."
function AnotherService () {
var AnotherService = {};
AnotherService.someValue = '';
AnotherService.someMethod = function (idParam) {
return $resource(apiUrl + ":action/:id", {}, {
get: {method: 'GET', params: {id:idParam, action: 'get'}
};
return AnotherService;
}
angular.module('app')
.factory('AnotherService', AnotherService);

Unit test, function in Angularjs Controller

I have a controller with a function and a promise and I've had a lot of problems testing it with jasmine and karma, please help! This is my service:
primaryDistributionApp.factory('gridData_Factory', ['$resource', function ($resource) {
return {
realTime:
$resource('/RealTime/', {},
{
"listAll": { method: "GET", params: {}, isArray: true }
}
)
};
}]);
And this is part of my controller (called gridInfo_Ctrl):
$scope.getData = function (){
gridData_Factory.realTime.listAll().$promise.then(function (data) {
$scope.data = data;
})
}
$scope.getData();
I'm trying to make a test in order to know if scope.data is Defined!
grab any dom element related to the controller, get its scope and test for Data.
var scope=angular.element($('cssquery')).scope();
i don't remember jasmine sintax correctly but would be something like
expect(scope.data).not.to.be.truthy;
and there you can perform several tests in your scope/

AngularJS factory not working

I have abstracted my working code from a controller into a factory, but it doesn't seem to be working and I can't find what's wrong. I opted for a factory rather than a service because I wanted to execute some code that defined the variable before returning that variable; I want to get result.station (a part of the data returned by the API), not the full result.
This is my code:
var app = angular.module("myApp", []);
app.factory('api', ['$http',
function($http) {
var station_list = [];
$http({
method: 'GET',
url: 'http://api.irail.be/stations/?format=json&lang=nl'
})
.success(function(result) {
station_list = result.station;
});
return {
Stations: function() {
return station_list;
}
};
}
]);
app.controller("myController", ['api', '$scope',
function(api, $scope) {
$scope.station_list = api.Stations();
$scope.title = "Stations";
}
]);
and a working example.
Try this:
.success(function(result) {
angular.copy(result.station, station_list);
});
You had a small error, you were replacing the array instead of populating it. I used angular.copy instead of the assignment in your factory and it works
http://plnkr.co/edit/sqgKcFZAcClmkfdXHhrz
The problem is that you are dealing with asynchronous nature of AJAX.
I would suggest to have a delegate method in controller, which will be called when the service call is complete.
Something like the following:
app.controller("myController", ['api', '$scope',
function(api, $scope) {
api.Stations( function(station_list) {
$scope.station_list = station_list;
});
$scope.title = "Stations";
}
]);
The following is a service method excerpt:
return {
Stations: function(delegate) {
if (delegate)
delegate(station_list);
return station_list;
}
};

how to call service method from ng-change of select in angularjs?

I am new to angular js. I am trying to call factory service method 'getScoreData' from ng-change of select, but not able to get it done. please help.
Html code:
<select ng-model="Score" ng-change="getScoreData(Score)" ng-options="c.name for c in Scores"></select>
Angularjs code:
var app = angular.module('audiapp', []);
app.controller('audiLayoutCtrl', function ($scope, ScoreDataService) {
ScoreDataService.getScoreData($scope.Score, function (data) {
$scope.ScoreData = data;
});
});
app.factory('ScoreDataService', function ($http) {
return {
getScoreData: function (Score, callback) {
var params = {
questionCode: Score.code
}
return $http({
url: 'Home/GetAvgData',
method: 'GET',
params: params
}).success(callback);
}
};
});
above is the service factory method and its instantiate from controller. I tried instantiating from ng-change of select but its neither giving error nor its getting called.
You have at least two issues in your code:
ng-change="getScoreData(Score)
Angular doesn't see getScoreData method that refers to defined service
getScoreData: function (Score, callback)
We don't need to use callback since GET returns promise. Use then instead.
Here is a working example (I used random address only for simulation):
HTML
<select ng-model="score"
ng-change="getScoreData(score)"
ng-options="score as score.name for score in scores"></select>
<pre>{{ScoreData|json}}</pre>
JS
var fessmodule = angular.module('myModule', ['ngResource']);
fessmodule.controller('fessCntrl', function($scope, ScoreDataService) {
$scope.scores = [{
name: 'Bukit Batok Street 1',
URL: 'http://maps.googleapis.com/maps/api/geocode/json?address=Singapore, SG, Singapore, 153 Bukit Batok Street 1&sensor=true'
}, {
name: 'London 8',
URL: 'http://maps.googleapis.com/maps/api/geocode/json?address=Singapore, SG, Singapore, London 8&sensor=true'
}];
$scope.getScoreData = function(score) {
ScoreDataService.getScoreData(score).then(function(result) {
$scope.ScoreData = result;
}, function(result) {
alert("Error: No data returned");
});
};
});
fessmodule.$inject = ['$scope', 'ScoreDataService'];
fessmodule.factory('ScoreDataService', ['$http', '$q', function($http) {
var factory = {
getScoreData: function(score) {
console.log(score);
var data = $http({
method: 'GET',
url: score.URL
});
return data;
}
}
return factory;
}]);
Demo Fiddle

Resources