Why are factories (singletons) in Angular not a bad design? - angularjs

Singletons are a bad idea for the most part. I believe everyone is on board with this concept. I am wondering why does Angular rely so heavily on factories for its dependency injection considering factories are singleons ? Why are singletons not a bad idea in Angular ?

Singleton is not considered a 'good practice' when accessed directly, through global class name (in java) or as a global variable. Your code is coupled with it and difficult to reuse and unit test. Changes in one class/module can cause a side effect in another one without you being able to execute those modules independently.
In Angular it is injected as a dependency - a function parameter. So it is a different thing. You can easily pass different implementation of you singleton to one function and different to another (if you wanted). Your code explicitly declares it as dependency and allows the client (caller) to pass whatever he wants instead of hiding it internally.

Related

Is it correct to access scope inside service or factory in angularjs

Disclaimer : I know there are certain questions which suggest not to access scope inside service or factory but here I am expecting the impact in terms of coding guidelines / whether it is advisable if not then I need proper justification.
We have angular js project and this project is old. Now after refactoring one of my colleague moved the common implementation from directive to service. While doing so , to access the scope of directive he manually started doing as below :
angular.element('<test-dir></test-dir>').scope();
What I felt is this is not the proper way to write the service/factory. I felt we are making the things complicated and suggested to remove the above part of code.
To justify the same I told :
1. This will make unit testability complicated and now we are trying to test the service the way we used to test directive.
2. And we are making this service tightly coupled with directive.
3. Service is not meant to access the scope.
But I think I am not able to convince him as I don't have much point to justify it. Can someone please suggest if I my understanding is correct and give proper justification to convice him. Thanks!
No, the services/factory are supposed to be working with data and should have the logic to process the data provided to them. Preferably, they should not refer to DOM objects or scope variables.
I personally believe that passing $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.
A Service is just a function for the business layer of the application. It acts as a constructor function and is invoked once at runtime with new, much like you would with plain JavaScript (Angular is just calling a new instance under the hood for us).Use a service when you want to just create things that act as public APIs.
The service class should work on the data provided by the controller, making it reusable at any other place if needed. Also keeping the scope away from it, keeps the code lean and clean thus better maintainability.
I prefer to put a domain object in the controller scope and pass that to the service. This way the service works irrespective of it being used inside a controller or maybe inside another service in the future.

Is there any such time when making a service accessible on the $root is acceptable?

Now, I know global variables is an anti-pattern, and perhaps more so in an Angular world than in other places... however, I have come across a use case where I'm leaning towards breaking the rule...
I have read the comments here, and strongly agree with all the posters who point out the anti-angular'ism my idea represents and the anti-pattern it generally is...
Angular JS - Make service globally accessible from controllers and view
However, now for my use case, I have a $theme service which contains a lot of variables and constants, such as paths to images and strings.
We also have a framework of components which are all made accessible to application designers via directives, allowing most of our applications to be build using just our internal framework in the form of markup directives.
I could make directives for each of the needs, however it would sacrifice the flexibility of having low coupling between views and themes, by allowing developers to access the $theme service directly in the views, without having to (re)write controllers (or even create controllers for everything) or implement new directives, it would allow them to work purely in the markup made available to them by the internal framework. Basically I want to enable application designers to be able to work purely in markup.
We also have made directives which wrap references to ngResource and exposes the methods of the resource on the current $scope as well as directives which binds the current $scope to variables on the $stateParam service, etc, etc, hopefully you get the picture...
e.g.
<h1>{{$root.$theme.NAME}}"</h1>
<img my-src="$root.$theme.logo.url" />
instead of lots of code with controllers and directives...
<my-theme-name />
<h1 my-theme-name />
<my-theme-logo />
<img my-theme-logo />
The difference between these two approaches is that the ones where the directive is attached a primary tag, it's purely a decorator, where in the former cases where the directive is the primary tag, the directive template will determine the resulting primary tag. A slight difference yielding a larger degree of flexibility in the approach where we are using the directives purely as decorators and not information experts.
However, instead of having to write directives all together, perhaps for things which are purely added to the individual theme, just to be used in a single app, in which case adding support in the $theme service seems to be wrong approach...
However, going with a strict custom directive driven approach, it will possibly allow us to more easily port to e.g. Angular2 or even something else by simply building an adapter or transpiler, without having to rewrite any of the markup, but simple rewire the directives to new controllers and handlers written in the new library.
So, back to my question, provided we work around this caveat for the testing, would it be a viable approach, or is it a slippery road to global variable hell where soon we will have polluted our $root with tons of things because it was the easy way ?
_____ Update 7th May 2016 _____
OK, I decided against making my theme service globally available when I suddenly was compelled to put my $fileSaver service out on the global scope as well, indicating the my fears of "scope-creep" were valid, instead I decided to implement a <my-injector my-name="$theme" /> directive which allows application designers to import services declaratively, the directive makes the injection target specified in the myName attribute available on the current scope.
It allows app designers to use the service anywhere in the scope like this:
<my-injector my-name="$theme" />
<img ng-src="$theme.logo.url" />
I thought about creating difference convenience directives, e.g. some app designers might find <my-import my-name"$theme" /> more intuitive, but that is a different discussion...
It's not an absolute necessity to avoid rootScope. From the Angular FAQ, with my emphasis:
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
Since your theme seems to be largely data, I say why not use root? If it does contain functions, is it possible to split it? I can't decide that for you, I haven't seen what you're actually trying to do...

pitfalls of IIFEs with AngularJS

I have an application made with angularJS, whole application is composed of IIFEs(Immediately Invoked Function Expression). Every module, directive, controller is itself an IIFE and they are around 100s.
I want to know what is the performance pitfall when an app has so many IIFEs.
It is OK to use IIFEs with AngularJS?
How good is using libs like browserify and requirejs with AngularJS for managing the dependencies?
Can you please throw some light on this?
The question you need to ask first is whether you've got some internal parts within the IIFE that you don't want to expose to the global scope.
The whole point of creating a closure in this manner is to mimic encapsulation and avoid polluting the global scope.
The performance pitfall is not so easy to measure; I think the performance issue is negligible when you create the IIFE (don't forget you're just creating a function). One performance issue that I might think of is that when you reference a function variable form an inner function, you need to travel through the scope chain and get it from the closure object.
I would recommend you to look at patterns like module pattern, revealing module pattern etc. I personally use the revealing module pattern.
Browserify and requireJS are two libraries that implement two different specs; the commonJS and AMD respectively. These two specifications try to accommodate a functionality that is not supported by ES3 or ES5; That is a way of defining module and then loading them in specified locations.
If you want to define modules and load them synchronously in a similar manner to hose nodeJS works, you can use Browserify. In addition, Browserify allows you to use the same modules both for client-side and server-side (as long as you're using nodeJS).
On the other hand if you want to asynchronously load your modules you can go with AMD and requireJS, but you won't be able to reuse them on the back-end.
Finally, bare in mind that everything you've mentioned is not directly connected to angularJS; those are some good JavaScript practises to overcome some issues of the language itself. It can be well used whether you're working with angular or not.
I would recommend that you use either browserify or requireJS; it will benefit you in the long run. Just imagine having 100 JS files; you would need to out the manually into your html in the correct order based on the dependency graph. You can easily come across issues like race conditions where one file should have been inserted before another one.
As for the performance overhead of IIFEs, you shouldn't have any serious issues.
As another answer said, IIFEs are a good general practice, independent of AngularJS.
If you're concerned about the performance of IIFEs, go ahead and check out these performance tests on JSPerf (or write your own):
http://jsperf.com/iife-antecedents-in-js
http://jsperf.com/immediate-anonymous-function-invocation
While some ways of IIFE creation are clearly much slower than others, I wouldn't worry about the performance of IIFEs unless you're in a large loop.

AngularJS: Using third party libraries without exposing a global variable

What is the best way to use a third party library in Angular without exposing a global variable?
For instance, if I were using underscore.js, I want to inject _ into only the controllers that use it.
angular.module('module').controller(function(_) {
// _ is injected only into this scope
};
To get this effect, I've seen some people load underscore globally with a script tag, then create a service like this:
myModule.factory('_', function ($window) {
return $window._;
});
However, this still pollutes the global scope with _.
Is there an 'Angular way' of registering and injecting third party libraries without causing this problem?
You can't do anything about how the third party libraries are written, except by forking them and creating your own version.
Third party libraries will almost always create such variables on the global scope, and you mention the two most frequently used ways of using them in an Angular module: by injecting $window and using them directly, or by creating a thin service which provides the object.
I would favor the latter in most cases because it makes the code in other modules simpler. Also, in my mind, the service approach makes the code in your controllers seem less 'magic' and more debuggable, as it is clear where the library, e.g. _ comes from. Variables appearing "out of thin air" is some of the problem with global variables to begin with.
The library will still "pollute" the global scope, unless you explicitly deletes them from the global scope, perhaps after fetching a pointer to them in a service, which then can pass it on. However, I can't see any motivation for doing so. Any other attempts, such as using an Angular service to actually download the third party script and evaluating it, somehow preventing it from reaching the global scope, seems vastly inefficient, over-engineered and slow (both computationally and with regards to when HTTP requests are fired).
It's otherwise a good idea not to create any more global variables than strictly necessary.
For third party libraries that support provide a noConflict function - such as Underscore and jQuery - you could use that to prevent global pollution in your Angular factory.
myModule.factory('_', ['$window', function ($window) {
var underscore = $window._.noConflict();
return underscore;
}]);
Since all services in Angular are singletons it means that the injector uses each recipe at most once to create the object. The injector then caches the reference for all future needs.
Put third party libraries in angular constants.
Keeps your code readable and clean and you can inject them in the specific controllers, directives,... where you want to use them.
angular
.module('sampleApp', [])
.constant('_', window._)
.constant('$', window.$)
As documented in John Papa's style guide [credits to #MaximilianoBecerra]
Miike is right, you can't "stop" a module from doing badness. Once anything calls window.whatever = ...
Require.js though is cool as async module definition library/methodology which helps people who are building packages do it without mucking in the global namespace. It won't help offenders, but it's neat.
http://requirejs.org/
I've created a tool which will create an angular factory rather than a global for all libraries that support require js. Since most libraries support require.js, I was able to write a function which mimics require's 'define' function, but rather than adding the library to require, it adds it as an angular injectable. It is practically plug n' play. Just include the js source after jQuery and angular and you're good to go. It's called angular global injector and available on github. Here's the link: https://github.com/btesser/angular-global-injector

Recycling AngularJS functions

I am pretty new with AngularJS, but was wondering how to create commonly used functions outside the scope of a controller.
For example, I pretty often need to call a function to start a "Loading" spinner (for RESTful calls, etc). I tried adding a showLoadingModal() function as a service, but those only seem good for retrieving data from what I've seen. Do I have to add this function to all of my controllers, or can you create app-level functions somehow?
You could define your common method on $rootScope, which will be available via prototypical inheritance to any child scope in your application.
Or, you could certainly define a service called "utilities" and just inject it wherever it's needed. Services are good for more than wrapping data-retrieval calls!
Of these two approaches, I would recommend the latter. More testable and less pollution of $rootScope.

Resources