I'm in process of learning Angular, so please forgive my naivety...
app.js in the angular-app example app references various dependencies in client/src/commmon/, such as services.breadcrumbs. How does Angular know to pull in these dependencies from the "common" directory? Is there some configuration I'm not seeing in this app?
Pertinent code:
angular.module('app', [
'ngRoute',
'projectsinfo',
'dashboard',
'projects',
'admin',
'services.breadcrumbs',
'services.i18nNotifications',
'services.httpRequestTracker',
'security',
'directives.crud',
'templates.app',
'templates.common']);
Take a look at https://github.com/angular-app/angular-app/blob/master/client/src/index.html
There you will see the following lines:
<script type="text/javascript" src="/static/jquery.js"></script>
<script type="text/javascript" src="/static/angular.js"></script>
<script type="text/javascript" src="/static/mongolab.js"></script>
<script type="text/javascript" src="/static/bootstrap.js"></script>
<script type="text/javascript" src="/static/<%= grunt.config.get('pkg.name') %>.js"></script>
This is where all of the packages are loaded. This is set up by Grunt, which is configured to concatenate JavaScript files together and create the files which are actually served. You should take a look at the Grunt configuration file (https://github.com/angular-app/angular-app/blob/master/client/gruntFile.js) to see how it is configured to do this. I don't know too much about Grunt yet, but if you know for what to look, you can find the configuration for concatenating various sets of files which are then placed in the distribution directory under the above referenced file names.
Angular dosen't have a dependency loader (yet).
all the script is being loaded from the first beginning. either as a bundle script, multiple <script> tags or being manual bootstrapped by another script loader
if I would create an angular app and want to use your code above, i would have to write
angular.module("myOwnApp", ["app"])
Now my app is a dependency of yours
and your app is depends on ngRoute, proj... so i have to load all your modules one way or the other
this is what I understand
Simply speaking, when you call:
angular.module('app',[
'ngRoute',
'projectsinfo'
]
angular will know you create a module app with dependencies of ngRoute and projectsinfo.
So when app is initiated, it will ask for these two dependencies from $injector, which is responsible for module dependencies.
So, when $injector is asked for these two module, it just look for them by the names, from something like a module POOL, $provide.
Simply put, when you define a module
angular.module('projectsinfo',[])
it actually just put a factory function, with the name 'projectsinfo' into the POOL. And the $injector will look for modules from it.
About the common derectory, since you load angular.js at the very beginning, so wherever you define a module by module, they all goto the same pool
In your example, services.breadcrumbs is not loaded from client/src/commmon. The scripts in client/source/common are loaded into the browser. On browser load, the scripts add themselves to the angular runtime (e.g. angular.module('service.breadcrumbs', [...])). Once a module is added to the angular runtime it is available for consumption by other angular modules.
Related
I just started learning AngularJS and got chance to look different angular examples. I have a question regarding angular.module dependencies. How can we know the name of dependencies to be used and from where (or which directory) angular inject those dependencies ?
for example
var clientApp = angular.module('clientApp', ['ui.bootstrap', 'hljs', 'common', 'smart-table',
'bootstrap.fileField', 'toaster', 'ngAnimate', 'angulartics', 'angulartics.google.analytics']);
in the above clientApp they have used nine dependencies. I am confused on the names used for injecting those dependencies like ui.bootstrap,hljs etc. Is there any standard convention for those names ? Also how angular fetch the required modules from lib folder ? This is my directory structure
+---js
¦ appctrl.js
+---lib
+---components
+---angular
¦ angular.js
¦ angular.min.js
+---angular-animate
¦ angular-animate.js
¦ angular-animate.min.js
+---angular-bootstrap
¦ ui-bootstrap-tpls.js
¦ ui-bootstrap-tpls.min.js
¦ ui-bootstrap.js
¦ ui-bootstrap.min.js
The clientApp will get all the modules without fail. I wonder how it can access these directory without specifying.
The injection of module dependencies depends on your code. Either one or more dependencies are injected based on the need of a code. If you are redirecting between pages using angular 'ngRoute' will be injected. If you are injecting 'ngRoute', you must specify "angular-route.js" in the script header. Another example is ngAnimate. This is used when an animation is required. This shall be used when a menu appears or disappears to make the transition smooth. The angular-animate.js should be added.
The ui-bootstrap is list of bootstrap components developed in angular. If you intend to use any of the directives in the following URL, you will inject the ui-bootstrap. https://angular-ui.github.io/bootstrap/
Toaster is a third part library. The another common one is gridster.
There are hundreds modules that can be injected into angular modules. Do inject only the modules that are used in the code as explained above. You must add related js files to your HTML script section. If you do not add the js script, angular code will not understand the injection.
Do let me know if you expect more details
The dependencies you are injecting to the module are named the same way your clientApp angular module is, because they are also angular modules.
So in your case, I could require your app by passing 'clientApp' into my module's dependency array.
As for the file fragments clientApp needs to require, it depends on how you build your app. You can wrap all of your JS in Immediately Invoked Function Expressions AKA IIFEs like such:
(angular.module(function () {}))()
Then you just have to include each script separately in your index.html the way you would any javascript file. Their names are declared roughly in the same way as the module. Ex:
.service('sampleSvc', ['$window', 'modalSvc', function($window, modalSvc){})])
When your IIFEs are executed, these functions are registered on your app module and can then be called by name. In this case, sampleSvc.
Or you can dive into the world of build tools... Personally, I like NPM to do everything and wrote all my own shell commands for each part of the build cycle. I prefer browserify in conjunction with that. However for someone just getting started, you might want to check out grunt and gulp. (Controversial opinion time: Gulp is faster)
Also: +1 to the recommendation to study John Papa's Angular Styleguide. If I'm not mistaken it was endorsed by the angular team. Also check out his ng-demos for more robust examples.
I have this Angular (1.3.15) code:
var my_app = angular.module('my_app', ["ui.bootstrap", "toastr"]);
my_app.module("template/foo/bar.html", []).run([$templateCache, function($templateCache) { /* ... global template ... */ }]);
which injects bootstrap and toastr libraries and creates a template that I use in all my other JS files.
Now, not all files need ui.bootstrap, but given the fact that I placed it in my global.js file (which is loaded with every page, no matter wat), Angular is complaining about missing libraries (ui.bootstrap).
My question is: can I inject ui.bootstrap only in the controllers I need it and leave my gobal.js like this:
var my_app = angular.module('my_app', ["toastr"]);
Also, this applies to quite some other libraries I'm currently loading in my global JS file, not only ui.bootstrap.
One approach to this is to split your code into multiple modules by some rule. This way only the modules that need ui.bootstrap will have it as a dependency, other won't.
If that's still not clean enough for you then you might want to take a look at Browserify
I have two JavaScript modules that I need to use in my web application. And I'm using Require.js to handle my module dependencies. As per Require.js tutorials I've went through, only one module can define in single JavaScript file. Because Require.js keeps those dependencies using the file name.
Eg:
require.config({
paths: {
"jquery": "lib/jquery-latest.min"
}
});
So as far as I know we can define one module per page. I have around 20 modules in my web application. Do I have to create separate JS file for each module ?
Thanks in Advance
I'd like to get some best practice advice on componetising sub modules into a larger project. In development mode, it works fine as require resolves all deps on the fly - but it needs to be produced for a GWT app now that apparently has difficulty consuming async stuff via callbacks.
Structure is as follows (this builds fine individually and creates the files as required):
main (builds all shared libs resources etc)
component A (requires main to be there but excluded in own build)
... component N
To be used in an app that loads like so:
<script src='require.js'></script>
<script src='main-lib-min.js'></script>
<script src='component-a-min.js'></script>
<script src='component-n-min.js'></script>
<!-- client to all these files is a single app to kick off: -->
<script src='app.js'></script>
main is defined as a require wrap and fires an event when done.
components are a collection of modules in a define() wrap.
the problem is, app.js should not reference anything until all references have been resolved. and component-A may have references to exports of main-lib so it should not be evaluated before the previous script has loaded.
in chrome, we are seeing parallel downloading and reference errors. need that to be blocking instead. since the r.js build has pre-packaged everything, the factory should be able to just return any module defined above it.
i.e. doing:
var foo = require('foo'); ought to be fine.
if app.js is created as:
require(['foo'], function(foo){
});
then it works.
does anyone have experience in producing this kind of a component build / module pattern? would you include all modules from the main-lib build config as modules: [] so they wait for each other? what if you want the client (i.e. the html file) to be the one adding the modules?
would you change the loading? is there a GWT loader that will be more appropriate to ensure sync-like behaviour? performance is not an issue.
I have a project with which I have just recently introduced RequireJS. Before RequireJS, I had been testing my project with Jasmine. I am now trying to update Jasmine's SpecRunner so that it can handle RequireJS.
I found this article on unit testing with RequireJS and Jasmine which I have used to get me started. I've hit a snag with how I am loading modules. Each modules defines other modules it has a dependency on, but each module's load path is relative to the location where requireJS was loaded.
I load requireJS in two different locations: background.html and SpecRunner.html. Background is for the main application and SpecRunner is for testing. The problem is that my modules fail to load when called from SpecRunner because their relative paths change.
Example:
js/third_party/jquery-1.7.2.min.js
js/background/player.js
js/background/playlists.js
tests/SpecRunner.html
tests/spec/PlayerSpec.js
background.html
With this folder hierarchy and files I have two scenarios. One in which the code runs properly and one in which there is an issue:
Good Scenario
background.html loads require.js and executes targeting player.js as the loading point.
player.js defines playlists.js as a dependency.
playlists.js is loaded.
player.js is loaded.
Bad Scenario
SpecRunner.html loads require.js and executes targeting player.js as the loading point.
player.js defines playlists.js as a dependency.
playlists.js fails to load. GET file://tests/playlists.js
The file location is incorrect. playlists.js is not under /tests, it is under js/background!
I'm not sure how I should handle this? It seems like being extremely explicit with path names is my only way out, but that goes against all of the requireJS examples.
Paths in require are relative to the data-main location or relative to the location of the function that called require(). In your good scenario this is js/background/, and in your bad scenario this is tests/. In the blog you linked they use require.paths to make this work properly:
<!--
Since we are in the "test" directory, not in the standard
"js" directory, we need to define the path prefix' for the
RequireJS modules so that the modules can be found from the
tests running in the Spec directory.
-->
<script type="text/javascript">
var require = {
paths: {
"domReady": "../js/lib/require/domReady",
"model": "../js/model"
}
};
</script>
In your case, you'll have to set up paths like
'player': '../js/background/player.js',
'playlists': '../js/background/playlists.js'
and explicitly require player and your spec in your test runner as they do in the blog post.