Service returning resources. Is it possible? - angularjs

Im trying a service returning multiple resources to be injected in a controller, but calling resource "query" method I get an error that method doesn't exist. below will find the code example of what I want to do. I do method call at controller side because there is additional logic when promise success. Is there a way to do that?
//Service
ImageRepo.factory('ServerCall', ['$resource', function ($resource) {
return {
Image: function () {
return $resource('/api/image/:id', { id: '#id'});
},
Meta: function () {
return $resource('/api/metadata/:id', { id: '#id'});
}
}
}]);
//Controller function
var ImageCtrl = function ($scope, ServerCall) {
...
$scope.metadefsearch = function () {
ServerCall.Meta.query().$promise.then(function (metasdef) {
$scope.metasdefinition = metasdef;
//Some additional logic.....
});
};
};

Let Meta and Image be objects instead of functions:
ImageRepo.factory('ServerCall', ['$resource', function ($resource) {
return {
Image: $resource('/api/image/:id', { id: '#id'});,
Meta: $resource('/api/metadata/:id', { id: '#id'})
};
}]);

Since your two properties are methods you should do this:
ServerCall.Meta().query().$promise.then(function (metasdef) {

Related

Setting function with dependencies when configuring provider in Angular

I want to develop a generic translator component with configurable url and paramsFn. Here paramsFn can either be a plain function or a function with service dependencies. paramsFn is expected to return a promise.
(function () {
"use strict";
angular.module("translator-app", [])
.provider(translatorProvider);
function translatorProvider() {
var
url,
paramsFn;
//Provider Config Functions
function setUrl (pUrl) {
url = pUrl
};
function setParamsFn (pParamsFn) {
paramsFn = pParamsFn;
};
function factory ($http, $q) {
//Service Function Pseudo
function translate(key) {
if (translateions are cached) {
//return promis of cached translations
} else {
/*
make http call with configured url and
paramsFnto fetch translations.
Cache translations.
Return promise with translations.
*/
}
} //translate
//Service Object
return {
translate: translate
};
} // factory
factory .$inject = [
"$http"
"$q"
];
//Exposed functionality
this.setUrl = setUrl;
this.setParamsFn = setParamsFn;
this.$get = factory;
}
}();
An application can use translator after configuring it. User app provide will be able to provide paramFn with service dependencies. paramFn will be invoked later when translator.translate(...) method is called.
(function () {
"use strict";
angular.module('the-app', ["translator-app"])
.config(translatorConfigurator)
.controller(AppController)
function translatorConfigurator (translatorProvider) {
function theParamsFn (someService) {
//use someService to generate and return params object
}
theParamsFn.$inject = [
"someService"
];
translatorProvider.setUrl("/url/to/translator");
translatorProvider.setParamsFn(theParamsFn);
}
function AppController (translator) {
translator.translate("the-key").then(function (translated) {
//do somethid with 'translated'.
});
}
translatorConfigurator.$injec = [
"translatorProvider"
];
AppController.$inject = [
"translator"
];
}());
How can I achieve this?
Short Story:
According to Angular $injector documentation
// inferred (only works if code not minified/obfuscated)
$injector.invoke(function(serviceA){});
// annotated
function explicit(serviceA) {};
explicit.$inject = ['serviceA'];
$injector.invoke(explicit);
// inline
$injector.invoke(['serviceA', function(serviceA){}]);
Novel
Once upon a time there was a poor translatorProvider. Angular, a great super hero, helped translatorProvider to be feature rich by its $injector weapon. translatorProvider built its getParameters function inside factory function and used it in translate.
(function () {
"use strict";
angular.module("translator-app", [])
.provider(translatorProvider);
function translatorProvider() {
var
url,
paramsFn;
//Provider Config Functions
function setUrl (pUrl) {
url = pUrl
};
function setParamsFn (pParamsFn) {
paramsFn = pParamsFn;
};
function factory ($injector, $http, $q) {
function getParameters() {
var
promise,
fn;
if (paramsFn) {
fn = $injector.invoke(paramsFn);
promise = $q.resolve(fn());
} else {
promise = $q.resolve()
}
return promise;
}
//Service Function Pseudo
function translate(key) {
if (translateions are cached) {
//return promis of cached translations
} else {
getParameters()
.then(function (params) {
return $http({
url: url,
params: params
});
})
.then(function (response) {
var extracted = ...; //extract field from response.data
//put extracted into cache
return $q.resolve(extractedField)
});
}
} //translate
//Service Object
return {
translate: translate
};
} // factory
factory .$inject = [
"$injector",
"$http"
"$q"
];
//Exposed functionality
this.setUrl = setUrl;
this.setParamsFn = setParamsFn;
this.$get = factory;
}
}();
Now translator can be configured as below.
(function () {
"use strict";
angular.module('the-app', ["translator-app"])
.config(translatorConfigurator)
.controller(AppController)
function translatorConfigurator (translatorProvider) {
function theParamsFn (someService) {
return function () {
//returns some parameters object
}
}
theParamsFn.$inject = [
"someService"
];
translatorProvider.setUrl("/url/to/translator");
translatorProvider.setParamsFn(theParamsFn);
}
function AppController (translator) {
translator.translate("the-key").then(function (translated) {
//do somethid with 'translated'.
});
}
translatorConfigurator.$inject = [
"translatorProvider"
];
AppController.$inject = [
"translator"
];
}());
After these changes translatorprovider becomes more powerful and help many other modules and they lived happily ever after.

Crud with angularjs and http service

I am starting to learn angularjs, so far i can create update delete withoud using services. I am trying to take it to the next level: Ive created a service page that looks like this:
app.factory('MainService', function($http) {
var getFeaturesFromServer = function() {
return $http.get('restfullfeatures/features');
}
var deleteFeature = function(id) {
return $http.post('restfullfeatures/delete', {'id': id});
}
var createFeature = function(feature) {
return $http.post('restfullfeatures/create', {'title': feature.title, 'description': feature.description});
}
return {
getHello : getHello,
getFeatures: getFeaturesFromServer,
deleteFeature: deleteFeature,
createFeature: createFeature
}
});
and my add function in controller looks like this:
$scope.add = function(){
MainService.createFeature($scope.formFeature)
.then(function(response) {
console.log('feature created',response.data);
$scope.features.push($scope.formFeature);
$scope.formFeature = {};
}, function(error) {
alert('error',error);
});
};
And this is my postCreate function:
public function postCreate()
{
\App\Feature::create(
['title' => \Input::get('title'),
'description' => \Input::get('description')
]);
return ['success' => true];
}
I have a table in my database called features, so basically what i am trying to do is add a new feature to my table using angularjs, my controller doesnt seem to recognize formFeature all i get is 'undefined' then i get the error: Cannot read property of type undefined, but I am using it in my delete function and it works perfectly, what did i miss here??
Factory
So when creating a factory for CRUD, try to lay out your factory like the example below. The example is some code I wrote for a project each call willl do a different thing, the idea is that you add a method that you can instantiate when you add the factory to your controller. (note: don't use $rootScope for session)
.factory('Chats', function ($http, $rootScope, $stateParams) {
return {
all: function () {
return $http.get('http://your_ip/chats', { params: { user_id: $rootScope.session } })
},
get: function () {
return $http.get('http://your_ip/chat', { params: { user_id: $rootScope.session, chat_id: $stateParams.idchat } })
},
add: function (id) {
return $http.post('http://your_ip/newChat', { params: {idfriends:id}})
}
};
});
Controller
when you instantiate this in your controller your looking at something like this
.controller('ChatsCtrl', function ($scope, Chats) {
Chats.all().success(function (response) {
$scope.chats = response;
});
$scope.getChat = function (id) {
Chats.get().success(function (response) { })
};
$scope.addChat = function (id) {
Chats.add(id).success(function (response) { })
};
})
$scope.remove and $scope.addChat and linked to buttons that will execute on click and $scope.chats is bound to the page via an ng-repeat.
Conclusion
Clean up your factories to look like this and you can easily write a series of reusable methods that are easy to instantiate in your controller.

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
}]);

caching services function so you dont repeat calling it

Is there a way to initialize some services in angular so that you dont have to repeat calling it? for example
services.factory('Util', ['$http', function($http) {
return {
countries: function() {
return $http.get('/utils/countries/');
},
ivas: function() {
return $http.get('/utils/ivas/');
}
};
}]);
I use this service in several controllers and it takes to long to load all the functions.
Thanks in advance.
You can use something like this, ensure the init method is called when you initialize your app by calling Util.init() then the data will be taken only once from the server, and you can use anywhere
services.factory('Util', ['$http', function($http) {
var me = {
data: {
countries: [],
ivas: []
},
init: function() {
me.data.countries = $http.get('/utils/countries/');
me.data.ivas = $http.get('/utils/ivas/');
},
getCountries: function() {
return me.data.countries;
},
getIvas: function() {
return me.data.ivas;
}
};
return me;
}]);

Add Prototype Function to ngResource in Angular Factory method

I'm trying to add a prototypal function to my ngResource factory method like this:
.factory('Magazine', function ($resource) {
var Magazine = $resource('http://localhost/dooleystand/ci/api/magazine/:magId', {
loginID : organEntity,
password : organCommpassword,
magId : "#magId"
});
Magazine.prototype.getLastAdded = function() {
return this.get({magId:"lastAdded"});
};
return Magazine;
})
Then I tried to call this factory method from a function in my controller:
Magazine.save(magazine, function() {
var newMagazine = Magazine.getLastAdded;
var tempMagazine = {
issue_number : newMagazine.issue_number,
magazine_name : newMagazine.magazine_name
};
$scope.magazines.push(tempMagazine);
});
It seems like my browser did not generate a new request at all. Any way to actually accomplish this or do I need to have a separate factory method?
How about extend the resource actions like this?
.factory('Magazine', function ($resource) {
return $resource('http://localhost/dooleystand/ci/api/magazine/:magId', {
loginID: organEntity,
password: organCommpassword,
magId: "#magId"
}, {
getLastAdded: { method: 'GET', params: { magId: 'lastAdded' } }
});
}

Resources