AngularJS: Using third party libraries without exposing a global variable - angularjs

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

Related

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

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.

Why do I need to inject the controllers I want in my app?

I am reading the source code for an app which reads as follows:
angular.module('graffio', [
'graffio.signupController',
'graffio.loginController',
'graffio.mainController',
'ui.router'
])
I have quite a few questions! So much confusion...
How is code loading these controllers which are defined later in the
code?
Why do I even need to state which controllers I want in my
app? Why can't I just have all the ones I declare?
Why does the angular documentation use the word 'injectable' so much? Isn't
injectable just the same as require?
With Angular, you can group as much or as little code into a module as you like. And you can compose modules together, like the author of the app you are looking at has done. The final module will have all of the services, config blocks, routes, controllers, directives, filters and so on that are in all of the modules it depends on as well as its own module.
This author has chosen to put each controller into its own module. Which is why the main module needs to depend on each of those modules. In my opinion, this seems like overkill, but it is what has been done, and all you need to do is understand it, not agree with it.
In answer to your other questions:
How is code loading these controllers which are defined later in the code?
When your code first runs, all the modules will be declared, and populated with directives, routes, controllers, services and so on. Nothing gets used yet. So long as when the code you have above is run, the other modules have already been declared then everything is fine (this may be done by a build process such as a Grunt task).
Then, when the document.ready event occurs, Angular looks through your HTML for an ng-app directive that says which module to load as your application. It then does what it calls the "bootstrap" process for that module.
Why do I even need to state which controllers I want in my app? Why can't I just have all the ones I declare?
Because this author has put each controller in their own module. If you put all the controllers you want into one module, then you don't need to declare them like that.
Why does the angular documentation use the word 'injectable' so much? Isn't injectable just the same as require?
Sort of. It is similar in that you are asking for a dependency by name and then using it.
It is different in that with require you can't typically modify what value is retrieved for a given dependency at runtime. With dependency injection, you can swap or modify dependencies at run time if you so choose (before your app starts properly and the dependencies are injected into the code using them).
This is perfect for testing, so that you can use a mock (fake) version of a dependency for testing purposes, instead of using the normal version. Think of a service that makes a call to get some data from the server and returns a promise. You can just create a mock version of that service that doesn't call to the server, just returns some test data immediately. This makes your unit tests fast, and means you don't need to be running your web server for them to work.

Why using $controllerProvider.allowGlobals() is generally not recommended?

When migrating from Angular 1.2 to 1.3, it's generally recommended that all your controllers are housed inside a module (otherwise they'll break) even though adding one line to the module's config can achieve the same thing:
angular.module('app').config(['$controllerProvider',function($controllerProvider) {
$controllerProvider.allowGlobals();
}]);
But it's not recommended as it may have implications in the future.
Is there another major reason why the latter method is not recommended?
It's to avoid unnecessarily polluting the global namespace, and to reduce the risk that other code, say from some non-Angular plugins, can interfer with yours.
Say you have a controller, MyController in the global scope. Some other bit of Javascript in that page can just set something like
window.MyController = window.alert;
which (depending on when the code runs) can break your Angular app.
When you use global functions as controllers, your functions are going to pollute the global namespace. There could be more chance of collision with other libraries.
That's the reason why in angular 1.3, its recommended to group controllers inside modules. In that way you won't be polluting the global namespace and also in terms of organising code, it's much modular as well. So it helps us to have minimal footprint in the global namespace.

Purpose of AngularJS Services

I'm new to AngularJS. I'm currently looking at the services. Some of these services look like the replace functions already available in JavaScript. For instance, the $timeout service. Why does AngularJS have these services? Is there a technical reason? Are there any advantages to this approach? I just don't understand the need for using these services.
Thank you for any help.
A service is a function or an object, with a set of methods, that could be used by several components (controllers, directives, filters, other services) of your application.
The main advantage that "wrapping" services like $timeout or $window have over their global functions equivalent is that they're injected by Angular, and can thus be mocked in unit tests, i.e. replaced by fake implementations.
Read the chapter about dependency injection in the angular documentation. Regarding the $timeout service in particular, its documentation explains what it does in addition to the native setTimeout() function.
Angular uses dirty check -- it keeps track of all variables that should be updated automatically and in case of any changes iterates through them as many times as needed (as there can be interdependence between observing variables). (To be precise if there are too many iterations something wrong is probably with your code and exception is raised).
The main reason behind $timeout is to signal to Angular engine that you will be making some changes to the observing variables in the callback. In case you would call normal timeout there is a way to inform Angular about those changes by calling e.g. $scope.$apply(function() {...}).
The other big reason, as #JB Nizet stated is that mocking is much easier.
Service is a way to store persistent information over your application.
unlike the $scope, which is an new child of $rootScope per each route\controller.
The purpose of the Angular-specific implementation of already existent functions, is to make your life and work easier, by automatically telling angular to register your changes, and apply them to the current scope at the next $digest iteration.
I'll be happy to address any other questions.
Good luck with Angular! :)
I will now create an example plunk to emphasize the idea to you
UPDATE:
This is the plunker:
http://plnkr.co/edit/mVmhZpEdsZDQ0MUQpFJ7?p=preview
I used ng-change and the native change
keyup event to explain the point.
while using the angular built in ng-change directive requires no additional effort nor code, using the native events requires wrapping everything in the scope.$apply function/
calling scope.$digest manually.
(run the code and see for yourself)
Check out this older answer which covers Services, Providers and Factories.
AngularJS: Service vs provider vs factory

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