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.
Related
Yesterday, I heard a colleague state that the factory in angular is not the same as the factory pattern. I'm curious about if this is a valid statement and why.
Normally factories will create you an instance of an object. From looking at our code, it looks like the factory is a wrapper or object that can be called for the related web services as well, so GET, PUT, POST, PATCH, DELETE. There are some instances, where this varies, however for the most part, it looks like something that helps interact with the related web services.
Having a factory that returns objects just based on "GET" seems like it would align more with a traditional factory pattern, but the fact that we deal with the other verbs, makes me think that is where things deviate from the pattern.
Can someone confirm if this is the standard way to use angular factories and if so, if my intuition/thoughts are correct, or if I'm missing something?
Update
There as a request to provide code as to what I'm talking about. I did some googling for angular factory examples, to see if others are doing similar stuff as to what I'm seeing at my work. Which I found the following example: http://weblogs.asp.net/dwahlin/using-an-angularjs-factory-to-interact-with-a-restful-service
When you look at the example, you'll notice that the "dataFactory" does not just have a GET, it has other HTTP verbs too. Is this bad practice from the user base, or is it the standard way to use it and the factory is different from the design pattern?
Factory is a recipe of Provider in Angular and a form of Factory pattern, which is simply a process of one object takes responsibility to create other objects.
The example you referred is also an implementation of Factory pattern though not ideal, dataFactory creates and returns a proxy kind object which will be used in another consuming class to perform CRUD operations. Don't confuse it with HTTP verbs which are nothing to do with Factory pattern. In other words, factory class can return an object that can contain any kind of operations.
An ideal way to implement factory class:
function Bird(type) {
this.type = type;
//constructor logic
this.fly= function () {
//other business logic
};
}
//Below class is a factory which creates object for requested Bird type
function BirdFactory() {
this.create = function(type) {
return new Bird(type);
};
}
Hope this clarifies.
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'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.
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.
I have a simple js array being retrieved by an angular factory, injected into a control, watched, then displayed in a table using ng-repeat from within a view state managed by ui-router.
Initially I attempted to subscribe to this array using $watchCollection...
self.$watchCollection( self.Data, function(newData, oldData){
self.total = newData.length;
});
However this was only running when I initially load the app. I found that the only way to subscribe to the running collection was to use an anonymous function returning the array in question.
self.$watchCollection( function() { return self.Data }, function(newData, oldData){
self.totalWatchedWithAnonFunc = newData.length;
})
View this all in http://plnkr.co/edit/L7mycl
From everything I read, all I should have needed to do for a valid subscription was to pass in the array itself and not an anonymous function that returns the array.
The reason I included ui-router is because my actual application is using it heavily and I wanted to mock up my environment as closely as possible to how I've got things set up.
What am I not understanding? Could I be doing something differently?
Thanks.
Are you looking for self.$watchCollection("Data", ...) instead of self.$watchCollection(self.Data, ...)? Try it out! See the docs to see why: the first argument is a string evaluated on the scope, or a function taking a scope that returns something you want to watch.