Is it okay to have a function as an Angular service? - angularjs

Usually AngularJS services are objects - no matter whether you create them using service, factory or provider.
Now I have a use case for a singleton function. Basically, I could solve this using a call to factory and by returning the function, such as:
angular.module('foo')
.factory('bar', function () {
return function () {
// ...
};
});
This works, and whenever I ask for bar I get the inner-most function. Anyway, the fact that it works does not mean that it's a good idea.
So, is it? Or is it a bad one? If so, why?

Why not use value or constant? According to the docs they can take functions too.
Register a constant service, such as a string, a number, an array, an
object or a function, with the $injector.
also from the docs of value:
This is short for registering a service where its provider's $get
property is a factory function that takes no arguments and returns the
value service.
So I assume your approach is also valid.

Related

Why functions are returned from angular services

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.

AngularJS providers having two different receipes

While reading up on AngularJs providers, I noticed that different authors use different receipes to descrive what AngularJS providers are.
These different receipes for defining "provider" is causing great confusion.
I have laid down the two different methods that I see in this plnkr:
http://plnkr.co/edit/ZelQLtRiibH1NqetSTqe?p=info
Also, the same are given below:
app.provider('provider1', function(){
this.$get = function(){
return "value from provider1";
}
});
app.provider('provider2', function(){
return {
$get: function() {
return "value from provider2";
}
}
});
As you will notice, in "provider1", I pass what seems like a constructor function.
In "provider2", I simply return a object.
Could someone help clarify what's going on here ?
After spending two days sifting through AngularJS source code, I finally found the solution. This is not a easy one or a obvious one. One has to know the source code for the framework quiet well in order to know the reason.
While registering a provider, you have the option of simply giving a object with $get property or a constructor function with $this method. Angular will handle both differently.
The provider constructor is instantiated right when it is registered. Hence if it has any dependencies that have yet not been registered then this method will fail.
In case of provider objects, this is not a must as the $get is executed lazily.
These are not interchangeable methods and both have their own use cases.
Based on the documentation, you may either provide a provider instance directly (your question is not concerned by this) or provide a constructor for the provider (both your examples do this).
The result of both your examples is essentially the same because of how constructor functions operate in JavaScript (pay attention to the paragraph starting with "The object returned by the constructor function becomes the result of the whole new expression.").
In the first example, method(s) are assigned to the default instance object, which then becomes the instance, as the constructor doesn't return any value. In the second example, constructor returns an object containing the method(s), which then becomes the instance.

Which Angular provider for function syntax?

Let's say I have a provider named lookup. It's used like this:
.controller('lookupCtrl', ['lookup', function(lookup) {
this.values = lookup('monkey');
}]);
What is lookup? Is it a service()? Is it a factory()? A value()?
In this particular case it can be any of those.
lookup could be a value if you created a regular, plain-old JavaScript object and then used the Value provider, naming your object "lookup". Even though a value is typically a simple type, it could be an object, and this would work.
lookup could also be a factory if you used the factory provider, in which case, you specify a function which returns an object. The object you return is the exact same object that's injected in any routine like the above that requests 'lookup'
And finally, lookup can also be an angular service. If you did that, the service provider would specify a function that returns a "newable" object. So the thing you return will be a function which Angular will "new", and the result of that will be passed to anyone who requests a 'lookup' instance. Note that, even in this case, Angular instantiates your service one and only one time. The difference between factory and service is subtle. Think of a service returning a "class" that angular instantiates once and reuses that one instance. And a factory uses the object that you returned to angular.
The answer is "D: All of the above"
As a service:
.service('myService', function(){
return function(someParam){
console.log(someParam);
};
});
As a factory:
.factory('myFactory', function(){
return function(someParam){
console.log(someParam);
};
});
As a value:
.value('myValue', function(){
console.log(arguments);
});
Here is a Plunkr... look at the console output.

What is the difference between angular.Module.factory and angular.Module.service when creating a service?

I'm getting re-acquainted with angular after a long time away, and (so far) I've discovered two ways to create an angular service. The simplest being this:
var app = angular.Module("SomeApp", [])
.factory("SomeService", function ($log) {
$log.info("Yea beh beh! Dis hea is a service!")
});
This form of creating a service in angular is documented in angular.Module.factory. But, you can also see, that on the same page there is another way to create a service, using angular.Module.service.
Reading the two descriptions, I am unable to understand the differences other than .service needs you to explicitly use new to instantiate a service, whereas .factory implicitly does it for you. I might be wrong here, since I'm unable to understand because I have no clue what a $get property is. So, to wrap up:
What is a $get property?
What is the difference between .service and .factory?
Lastly, because this bugs me:
With all angular.Module.{service, factory, controller}, the second argument is a function. But, for instance, you have put in a list for the second argument in a controller, and name its dependencies. Then why is the type taken to be a function, rather than object? I mean you won't know from the documentation that you can declare dependencies in a list unless you've done a tutorial or something.
Both angular.Module.factory and angular.Module.service are proxies to angular.Module.provide. When you give a function to angular.Module.factory angular creates the respective service by invoking the function and using its return value as the service. On the other hand, when you give a function to angular.Module.service angular will treat it as an constructor and invoke it with the new keyword to create the service.
Thus creating a service with angular.Module.factory looks like this:
app.factory('MySimpleService', function () {
return {
aServiceProperty : 'a property containing a string'
};
});
And creating a similar service with angular.Module.service looks like this:
app.service('MyOtherSimpleService', function () {
this.aServiceProperty = 'a property containing a string';
});
The definition of the $get propery can be found here
Looks like this question has already been asked and answered. I am unable to comment, so I posted an answer.

Updating 'this' Context Property Inside of a $Promise In An Angular JS Service

I have a function being used in my service that is defined as:
var getData = function() {
return anotherService.getData().$promise;
};
and a this property that I manipulate throughout the service.
this.someProperty = 'a string';
I call the above function inside the return section of my service:
return{
updateProperty: function(){
getData().then(function(data){
this.someProperty = data;
});
}
}
In the above, I get an this is undefined related error in my browser console. I assume this is because the resolved $promise is an AJAX call and this is used out of context. What's the best way to manipulate a this property using the returned data from an AJAX call in this instance?
if you're manipulating this throughout your service, assign it to a variable like var self = this. The problem is that this is the context of a function and can be changed by other code using fn.call(context) or fn.apply(context, args). So it's liable to be different inside of the scope of any given function.
So just assign it to some variable and use it:
var self = this;
return {
updateProperty: function(){
getData().then(function(data){
self.someProperty = data;
});
}
};
The simplest way would be to use the bind function. This function sets the 'this' context for the function call. So, in your case you'd have to use it twice so that the proper 'this' populates in.
return{
updateProperty: function(){
getData().then((function(data){
this.someProperty = data;
}).bind(this));
}
}
This comes to ensure that the handler you passed to the promise is executed with the original 'this' (passed to updateProperty). Now, to pass the correct 'this' value to the updateProperty function, you should, in your controller do:
(myService.updateProperty.bind(this))();
There are numerous versions of binding, including binding the entire service. Also, have a look at lodash for function extensions.
I prepared a small pen to demonstrate this. It covers what I listed above, plus another important thing to note. When you use setTimeout, the handler is invoked with in the global context (in this case, 'window'), this is why I added a third bind, to make sure 'this' is relevant inside the timeout handler. I also added various count increment calls to demonstrate that 'this' is the same value along the way.
If this is a repeating scenario, you might want to pass either the target object (and then use the handler just to know it was updated), or a handler (which also needs binding). I added examples for these scenarios as well.
One last word, call, apply and bind are key to javascript and worth learning. Put some time into it and work your way out of context hell.

Resources