If I need to use IIFE, why doesn't Angular use it? - angularjs

In John Papa's style guide he mentions the need to wrap every component in (function(){..}). This adds a couple lines to my code which makes me worried but not enough to justify a long work-around.
However, when I look at the actual Angular Code like the code for $compile and controller, I don't see these declarations.
Why is it important for me to isolate my variables with IIFE if Ng doesn't see it as important? Or a better question is why doesn't Angular implement IIFE?

Angular does use IIFE it wraps the code in
(function(window, document, undefined) {'use strict';
...
})(window, document);
So this distinguishes and protects the global/outer context and environment as a whole for all angular code
You can verify here
So it is wrapping the entire app right? But it isn't wrapping the
individual components
To answer your question, these components are not in separate files and are contained in single IIFE
the separate modules like angular-route, ng-resource are separated with angular.module() namespace or modular pattern from the global context

I think the answer may be, it depends.
First of all, AngularJS has to expose angular for the user to use, so it cannot be inside an IIFE. (just like jQuery exposes $ and jQuery, although it has an option that it only exposes jQuery).
And then, if you do decide to go with AngularJS, it won't be surprising that AngularJS expose some other stuff to the global space. But so far I have used AngularJS, I have only seen angular being exposed and all the things I do, I do it as
angular.module()
.controller()
.directive()
.factory()
.service();
and $compile is not exposed to the global space.
You only use IIFE to create a local scope so that the variables will not become part of the global scope.

Related

Registering AngularJS components via providers

I'm implementing an Angular/RequireJS routing solution based on Dan Wahlin's article.
In the article, Dan makes the following register shortcuts on his app object:
app.register =
{
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
When I use these, I can correctly register and reference my controllers through RequireJS calls, but if I use the traditionall app.controller() or angular.module('myApp').controller() syntax, then Angular can't find them and I get errors from the router.
How is defining controllers, directives, etc. with the above method different, and why does it work with RequireJS where the more traditional method does not?
Any ideas?
Thanks,
-Nate
Since the controllers are being added dynamically things have to change a bit from the "norm" (unfortunately). The main difference is that controllers are being wrapped in RequireJS modules, being downloaded dynamically, and then being registered. The $controllerProvider.register allows for the dynamic registration. It's definitely not the normal technique but what's required in this scenario. That's why "app" (which is the RequireJS module that gets us to the application's AngularJS module) is passed in to all of the controller modules. It exposes the controller property shown above which handles the registration "on the fly".
If you download a controller script dynamically and then use the normal technique (angular.module('..').controller(..)) it won't register it properly - at least that was the case the last time I tried it. It's been several months since I've tried it but I'm assuming the same behavior is still there.
The bottom line is that when controllers (and other items such as services/factories) have scripts that are loaded "on the fly" things change somewhat and the way you access and register these items changes from the normal way that we're all used to seeing.

Lazy loading AngularJS modules with RequireJS

Thanks to the great article from Dan Wahlin, I managed to implement lazy loading of Angular's controllers and services. However, there does not seem to be a clean way to lazy load independent modules.
To better explain my question, assume that I have an app would be structure as below without RequireJS:
// Create independent module 'dataServices' module with 'Pictures' object
angular.module("dataServices", []).factory("Pictures", function (...) {...});
// Create 'webapp' ng-app, with dependency to 'dataServices', defining controllers
angular.module("webapp", ['dataServices'])
.controller("View1Controller", function (...) {...})
.controller("View2Controller", function (...) {...});
Here is the sample app with RequireJS in Plunker:
http://plnkr.co/aiarzVpMJchYPjFRrkwn
The core of the problem is that Angular does not allow adding dependency to ng-app post instantiation. As result, my solution is to use angular.injector to retrieve the instance of Picture object to be used in my View2Controller. See js/scripts/controllers/ctrl2.js file.
This creates 2 problems for me:
The injected services runs outside of angular and therefore all async call must end with $scope.$apply()
Messy code where some object can be injected using standard angular syntax while others require the explicit use of injector.
Have any of you figured out how to lazy load independent module using RequireJS and somehow hook this module in angular so normal angular dependency injection syntax can be used?
Note:
The question is on lazy loading of independent module. One simple solution to this specific example is to create "Pictures" object using cached $providers during ng-app.config but that is not what I am looking for. I am looking for solution that works with 3rd party module such as angular-resource.
I finalized my own implementation called angularAMD and here is the sample site that uses it:
http://marcoslin.github.io/angularAMD/
It handles config functions and out of order module definitions.
Hopefully this can help other looking for something to help them with RequireJS and AngularJS integration.
Take a look at my project in GitHub: angular-require-lazy
This project is intended to demonstrate an idea and motivate discussions. But is does what you want (check expenses-view.js, it loads ng-grid lazily).
I am very interested in comments, ideas etc.
(EDIT) The ng-grid Angular module is lazy loaded as follows:
expenses-view.js is loaded lazily, when the /expenses route is activated
expenses-view.js specifies ng-grid as a dependency, so RequireJs loads ng-grid first
ng-grid is the one that calls angular.module(...)
In order to accomplish this, I replaced (proxied actually) the real angular.module method with my own, that supports laziness. See bootstrap.js and route-config.js (the functions initLazyModules() and callRunBlocks()).
This implementation has its drawbacks that you should be aware of:
Config functions are not implemented (yet). I do not know if it is possible to lazily provide config-time dependencies.
Order matters in definitions. If service A depends on B but A is defined after B in your module, DI wil fail. This is because the lazyAngular proxy executes definitions immediately, unlike real Angular that makes sure dependencies are resolved before executing the definitions.
It looks like the Node.js module ocLazyLoad defines a way of doing this lazy-loading, though I'm not sure how it fares, performance-wise, compared to the methods in the other answers or hard-coding the dependencies. Any info on this would be appreciated. One interesting thing is that the other answers need RequireJS to operate, while ocLazyLoad doesn't.
It looks like ocLazyLoad defines another provider that injects the dependency after the containing module has already been instantiated. It seems to do this by essentially replicating some low-level Angular behavior, like module loading and providing, hence why it looks so complicated. It looks like it adds just about every core Angular module as a dependency: $compileProvider, $q, $injector, ng, and so many more.

Is it possible to create an AngularJS service without a module?

In AngularJS there is a short form to create controllers, so you do not have to use a module for this. This short form is to simply define a function
function FooController ($scope) {
// ...
}
and reference it from the HTML markup using ng-controller:
<div ng-controller="FooController">
...
</div>
Now, my question is, whether there is a similar "short form" to define services? In other words: Can you define (and use) a service without using a module?
Please note that I know that it perfectly makes sense to structure your applications using modules, and not doing so could / should be regarded as bad practice. It's just that I am explaining AngularJS to someone who's completely new to it, and the question arose today. So it's just for curiosity and completeness.
Quoted from the doc of Creating Services
To register a service, you must have a module that this service will
be part of.
So I guess the answer is no.
Since the ng module is always loaded, you could define your service on the ng module:
angular.module('ng')
.service('aService', function () {
// you really shouldn't do this
});
It works, but you shouldn't be messing with a module that you don't own.
If you're trying to explain to someone why using your own modules with .controller is good:
Talk to them about testing. It's a lot easier to mock things if you're using modules
If you need to have other modules as dependencies (like angular-ui)
If you want to decorate another service (e.g. $http)
If you need to register directives, filters, animations, etc.
It's a lot nicer to have modular code :)
It's an angular concept I don't understand at all, I always believed "separation" is good, so I dont get why we need to associate a service to a specified application.
Here what I am doing: you can declare your angularjs application as a global object:
window.markrApplication = angular.module('markrOptionsApp', ....)
And declare all your services like this:
markrApplication.service('data', ....
Of course you need to have all the dependencies set on all your angularjs application.

what can or cannot be done with a controller created in a module Vs controller created globally?

Have seen various angular JS examples and I get the hint that I should define controllers on a module rather than a global definition.
Say I have an app that has <body ng-app='mymodule'> - inside body it can acknowledge controllers created in mymodule and controllers created globally.
The controller defined on the module will not have access to any global
variables as compared to the global controller. True/False ?
Any other important points to note here ?
The controller defined on the module will not have access to any global variables as compared to the global controller. True ?
False. Global variables are, well, global. You can access them from within the controller, but you shouldn't, unless testing isn't a concern for you - and it definitely should be.
Any other important points to note here ?
A global controller cannot use services from other modules but from Angular itself. If you want to use components defined in another modules (directives, factories, providers, etc.) you'll have to create your own module and declare them as dependencies so you can inject the bits you need wherever you need them.
The only use for a global controller, IMO, is to demonstrate Angular in a simple, easy-to-understand way. Don't use it in production.
Update
As #dotnetcoder pointed out in the comments, apparently due to the way Angular loads modules, a global controller can actually access the services from a module if that module was already loaded by the framework. I stand corrected. But, although technically possible, I can't think of any reason anyone should do that and I stand by what I've said previously: don't use global controllers in production.

What is the difference between service, directive and module?

I have been reading a lot of docs, and I'm getting more and more confused.
I basically can't figure out the difference between a
service
directive
module
I see a lot of custom components. Sometimes they're using directives, sometimes services. It always starts with a module. Can someone explain with an example what the difference is between these three types?
From my own personal notes (mostly snippets from the docs, google group posts, and SO posts):
Modules
provide a way to namespace/group services, directives, filters, configuration information and initialization code
help avoid global variables
are used to configure the $injector, allowing the things defined by the module (or the whole module itself) to be injected elsewhere (Dependency Injection stuff)
Angular modules are not related to CommonJS or Require.js. As opposed to AMD or Require.js modules, Angular modules don't try to solve the problem of script load ordering or lazy script fetching. These goals are orthogonal and both module systems can live side by side and fulfill their goals (so the docs claim).
Services
are singletons, so there is only one instance of each service you define. As singletons, they are not affected by scopes, and hence can be accessed by (shared with) multiple views/controllers/directives/other services
You can (and probably should) create custom services when
two or more things need access to the same data (don't use root scope) or you just want to neatly encapsulate your data
you want to encapsulate interactions with, say, a web server (extend $resource or $http in your service)
Built-in services start with '$'.
To use a service, dependency injection is required on the dependent (e.g., on the controller, or another service, or a directive).
Directives (some of the items below say essentially the same thing, but I've found that sometimes a slightly different wording helps a lot)
are responsible for updating the DOM when the state of the model changes
extend HTML vocabulary = teach HTML new tricks. Angular comes with a built in set of directives (e.g., ng-* stuff) which are useful for building web applications but you can add your own such that HTML can be turned into a declarative Domain Specific Language (DSL). E.g., the <tabs> and <pane> elements on the Angular home page demo "Creating Components".
Non-obvious built-in directives (because they don't start with "ng"): a, form, input, script, select, textarea. Under Angular, these all do more than normal!
Directives allow you to "componentize HTML". Directives are often better than ng-include. E.g., when you start writing lots of HTML with mainly data-binding, refactor that HTML into (reusable) directives.
The Angular compiler allows you to attach behavior to any HTML element or attribute and even create new HTML elements or attributes with custom behavior. Angular calls these behavior extensions directives.
When you boil it all down, a directive is just a function which executes when the Angular compiler encounters it in the DOM.
A directive is a behavior or DOM transformation which is triggered by a presence of an attribute, an element name, a class name, or a name in a comment. Directive is a behavior which should be triggered when specific HTML constructs are encountered in the (HTML) compilation process. The directives can be placed in element names, attributes, class names, as well as comments.
Most directives are restricted to attribute only. E.g., DoubleClick only uses custom attribute directives.
see also What is an angularjs directive?
Define and group Angular things (dependency injection stuff) in modules.
Share data and wrap web server interaction in services.
Extend HTML and do DOM manipulation in directives.
And make Controllers as "thin" as possible.
Think of a module as being a place to wire up a number of other things, such as directives, services, constants etc. Modules can be injected into other modules giving you a high level of reuse.
When writing an angular app, you would have a top-level module which is your application code (without templates).
Services are mainly a way to communicate between controllers, but you can inject one service into another. Services are often used as a way to get to your data stores and people will wrap the angular APIs, such as ngResource. This technique is useful since it makes testing (particularly mocking) quite easy. You can have services for doing other things like authentication, logging etc.
Directives are used for creating widgets or wrapping existing things like jquery plugins. Wrapping existing plugins can be a challenge and the reason you would do this is to establish a two-way data binding between the plugins and angular. If you don't need two-way data binding then you don't need to wrap them.
A directive is also a place for doing DOM manipulation, catching DOM-events etc. You should not be doing DOM-related stuff in controllers or services. Creating directives can get pretty complex. IMHO, I recommend first looking at API for something that can do what you are looking for OR ask Angular's Google Group for advice.

Resources