While defining a angular services, one is expected to pass a Constructor function. This constructor function would be initialized using "new" keyword and the object returned by "new" is set to the service. so far so good.
However often I come across instances where programmers are creating services as below:
app.service('aObj', function AClass(){
return function(a,b){
alert(a + b);
};
});
This would be called as
aObj(1,2)
Although I undertsand that aObj will now end up being a function, I cannot understand why programmers initialize their services this way. Constructor functions usually would have a definition like:
app.service('aObj', function AClass(){
this.var1 = undefined;
this.calculate = function(b){
alert(this.var1 + b);
};
});
Then eventually one would call this as
aObj.var1 = 1;
aObj.calculate(2);
Can someone elaborate on the purpose of defining services using the former method ?
Plnkr: http://plnkr.co/edit/tpl:FrTqqTNoY8BEfHs9bB0f
This depends on what kind of API you want to expose from your service.
Return an object and call them as MyService.methodA() and MyService.methodB() if the service is a container for exposing several closely related methods. Angular's $location service is an example of this.
If the service exposes only a single public method, then it can be more convenient for users of the service to call it as MyService() rather than MyService.theOnlyMethod(). Angular's $compile service is an example of this.
Related
Pls refer - http://jsfiddle.net/36qp9ekL/629/
I am using a factory method so that i can hide the implementation logic, private(pvt) variables and all the pros that factories are meant for.
If you run the code and see the console, I am able to view pvtvar1 and pvtvar2. How do I actually hide the pvt variables, implementation details.
app.controller("mycontroller", function($scope, myfactory) {
console.log(myfactory);
});
If you could tell the advantages of factories over services, would be helpful.
app.factory("myfactory", function() {
var pvtvar1= 3;
var pvtvar2 = 4;
return {
a:function(){
return pvtvar2 + pvtvar1;}
}
});
You are declaring the object and the function on the same scope of the variables. That's why they are shown. Here I declare the function on the object's scope. Take a look at this for more details http://toddmotto.com/mastering-the-module-pattern/
As you know, there are no privates in javascript. You are using closure to create inaccessible variables and functions. This is as good as you'l get. The console may show you (depending on the browser) properties that are defined via closure, but the important thing is, these properties aren't accessible in your code.
Advantages of a service over a factory? You can create an injectable service from a js object instead of a function so you can create services that inherit functionality. Not terribly useful since the injectable model is a replacement for inheritance in many ways but it's still an option.
I exclusively write services instead of factories but I'm using typescript in my projects (which has privates ;))
I have an angular module that contains some 'private' services. Those private services are only needed by other services in the same module and it makes sense to expose them for testing. But I don't want other modules to use this services.
Is there any possibility to mark such services 'private'? Is there at least a convention to name this services so that others recognize them as private?
If the only reason you need these "classes" to be angular Services is to have their dependencies injected painlessly, you could use $injector.instantiate to instantiate them without registering them as services.
Sample Code:
var PrivateClass = (function () {
function PrivateClass($log) {
this.hello = function () { $log.debug("Hello World!");}
}
PrivateClass.$inject = ["$log"];
return PrivateClass;
})();
angular.module('TestApp', []).run(['$injector', function ($injector) {
var p = $injector.instantiate(PrivateClass);
p.hello();
}]);
You would use $injector.instantiate(PrivateClass) in the constructor (or anywhere) within the services that need it, to create an instance of the PrivateClass. If you need PrivateClass to behave like a singleton (like a real angular service), you could use an accessor class that instantiate it once and returns its reference to callers.
The advantage of this is that you need not pollute the instantiating service's (in this case the function passed to angular.run), dependency array with dependencies that are only needed so they could be passed on to the PrivateClass ($log in this case).
I noticed that this is an year old question but, I found this while looking for a way to achieve exactly the above and ultimately solved it using this approach.
I am new to angularJS and going through angular docs.I came across this line controllers are created using a factory function
I tried to find what that means and found what is factory and service and providers but that does not fit here.
How controllers are created using a factory function?
Please explain what is the meaning of factory in this context.
The key quote you are missing from the previous section you are referring to is this:
"First, there is a new JavaScript file that contains a so-called "controller". More exactly, the file contains a constructor function that creates the actual controller instance. "
If this were an actual angular factory, it would make more sense. But, controllers are instances just like Angular factories, services, and providers.
A factory, is actually a Javascript design pattern, maybe reading here it will make more sense.
For the controller to work, the instance must exist for the two-way binding to be able to take place. So basically, an instance of the controller is created. The angular controller page explains it well with:
"When a Controller is attached to the DOM via the ng-controller directive, Angular will instantiate a new Controller object, using the specified Controller's constructor function. A new child scope will be available as an injectable parameter to the Controller's constructor function as $scope." Here's the link.
In the event of controllers though, you would most likely store items on the $scope and not 'this'. So they separate controllers from factories this way as they do not return an accessible instance of themselves and instead bind their properties to the view through $scope or 'this'.
TO BE CLEAR, I'm not saying that they are referring to Angular factories. I believe the reason for this phrasing is tied to the same wording for the service factory function:
"Application developers are free to define their own services by registering the service's name and service factory function, with an Angular module.
The service factory function generates the single object or function that represents the service to the rest of the application. The object or function returned by the service is injected into any component (controller, service, filter or directive) that specifies a dependency on the service."
They give this example:
var myModule = angular.module('myModule', []);
myModule.factory('serviceId', function() {
var shinyNewServiceInstance;
// factory function body that constructs shinyNewServiceInstance
return shinyNewServiceInstance;
});
So when you see them say created from a factory function, they are just saying using the following pattern:
.controller('PersonCtrl', [
'PersonFactory'
function(PersonFactory) {
this.name = 'Tom';
console.log(PersonFactory.name); //would print 'Tom'
}]);
.factory("PersonFactory", [
function () {
return {
name: 'Tom'
};
}]);
I hope that helps, or maybe someone could be more concise in my explanation and edit this description.
What this means is that you provide AngularJS with a function that it can execute as many times as it needs to produce instances of your controller. So to take the example from the page you linked to:
angular.module('invoice3', ['finance3'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = currencyConverter.currencies;
this.total = function total(outCurr) {
return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
};
this.pay = function pay() {
window.alert("Thanks!");
};
}]);
That function that starts on line 2 with function(currencyConverter) { is the factory function.
Whenever the page has a location that uses an InvoiceController, AngularJS will (essentially) do the following with that factory function, passing in any dependencies that it has:
var currencyConverter = ...; // obtain a currency converter from the factory
var theController = new thatFactoryFunction(currencyConverter);
and then it will use the value that is returned as your controller. It will do this separately for each InvoiceController indicagted the page, creating a separate instance for each one.
(I stress that the code above is purely an illustration of what AngularJS is doing and not an actual representation of the code that it uses.)
The creation of a controller instance is interesting. One would expect that it is created with new InvoiceController(...), and it's also suggested by the sentence More exactly, the file contains a constructor function that creates the actual controller instance, but that's not the case. Actually it's created like this:
instance = Object.create(controllerPrototype);
and later the constructor function is called as function:
return fn.apply(self, args); //self == instance
To be honest, we can only guess what the author meant by factory function. It could be the fact that controllers are not created by new. Maybe the the constructor function is therefore referred to as factory or it's the internal factory function. It could also just be bad wording or even a mistake.
So, this isn't the typical question of HOW to do it. I know it can be done with a service or a factory but I was wondering if someone could share what the advantages/disadvantages would be of just creating a basic service, injecting it into each controller, and then extending the service with functions from each controller. Something similar to the following example..
app.service('HelperService', function() {
return {};
});
app.controller('Controller1', function($scope, HelperService) {
$scope.somefunc = function() {
//do stuff here
};
HelperService.somefunc = $scope.somefunc;
});
app.controller('Controller2', function($scope, HelperService) {
HelperService.somefunc();
});
This works, and works well. I feel a bit stupid for asking this but it just seems like I'm missing something here as to why this isn't used or recommended?
It may work, but its a bad idea.
Controller2 HelperService.somefunc() won't exist until Controller1 has been instantiated. So theres an implicit dependency of Controller2 on Controller1
the code on HelperService isn't in one place where it can be understood together
if you are doing some sort of data manipulation in that function, it really should be operating on data encapsulated by the HelperService.
The service is a singleton and it will be instantiated once calling new on the function itself -- the function you pass in is essentially a constructor. This will create the empty object you are returning for use everywhere, but if you want to return an object in such a way it makes more sense to use .factory, but this is not a big deal.
At any rate, you can consider your code to conceptually do this:
var HelperService = function () {}
var helperService = new HelperService;
function Controller1() {
helperService.someFunc = function () {}
}
function Controller2() {
helperService.someFunc();
}
I would consider this a dangerous thing to do for a couple of reasons:
Controller1 must be instantiated before Controller2 or else somefunc won't be available to Controller2. Ideally the controllers would have no knowledge of each other.
You are coupling Controller/ViewModel (since you're using scope) with service level logic, but these should be decoupled. HelperService shouldn't know about the controllers either. Instead, you should be injecting a service that has an API that the controllers expect to use. This doesn't always have to be HelperService, it just has to look like HelperService to the controllers and its API shouldn't change.
Without knowing specifics about what you're trying to do, it's hard to advise. In general you may rethink what you want to do, but you can extend functionality of services with other services. Consider services to be in their own layer.
Is it correct to pass the "current" $scope to an AngularJS service?
I'm in the situation where I've a $service knowing it's consumed by only one controller, and I'd like to have a reference to the controller's scope in the $service methods themselves.
Is this philosophically correct?
Or I'd better to broadcast events to the $rootScope and then make my controller listen to them?
To let the controller know when something async happens, use Angular promises.
To provoke the $apply, you don't need the scope, you can call $rootScope.$apply, as there is no difference calling it in a specific scope or in the root.
Regarding the variable reading, it would be better if you received parameters. But you could also read it from a scope as an object parameter, but I would go with parameter, that would make your service interface much more clearer.
I would say if your functionality is specific to one controller only than you don't need a service.
The controllers tasks is to manipulate the specific model whereas a service should deal with global tasks. I would rather stick to this paradigm instead of mixing things up.
This is what the docs say
Service
Angular services are singletons that carry out specific tasks common to web apps
Controller
In Angular, a controller is a JavaScript function(type/class) that is used to augment instances of angular Scope, excluding the root scope.
PS: Apart from that if you need to digest you can also inject the $rootScope within your service.
Yes. You can pass the $scope into the service when you initialize it. In the service constructor you can assign the scope to something like this._scope and then reference the scope within the service!
angular.module('blah').controller('BlahCtrl', function($scope, BlahService) {
$scope.someVar = 4;
$scope.blahService = new blahService($scope);
});
angular.module('blah').factory('blahService', function() {
//constructor
function blahService(scope) {
this._scope = scope;
this._someFunction()
}
//wherever you'd reference the scope
blahService.prototype._someFunction = function() {
this._scope['someVar'] = 5;
}
return blahService;
});
I personally believe that passing the whole $scope to a service is a bad idea, because it creates a kinda circular reference: the controller depends on the service and the service depends on the scope of the controller.
On top of being confusing in terms of relations, things like this one end up getting in the way of the garbage collector.
My preferred approach is to put a domain object in the controller scope and pass that to the service. This way the service works regardless whether it's used inside a controller or maybe inside another service in the future.
For example, if the service is supposed to push and pop elements from an array errors, my code will be:
var errors = [];
$scope.errors = errors;
$scope.myService = new MyService(errors);
The service interacts then with the controller by operating on errors.
Of course I've got to be cautious about never wiping out the whole array reference, but at the end of the day that's a general JS concern.
I'd never want to use broadcasting, $apply and/or similar things, because imho good OO-practices will always trump whatever Angular-magics.