Currently looking at upgrade paths from Angular 1 -> Angular 2 and one things we've done with our Angular 1 work is reuse some of our components on public facing non-app pages.
These pages are effectively static HTML (though they are rendered by Rails) and then some Angular 2 components are dropped into the page in places. This worked from with Angular 1, we simply bootstrapped the document element with a module that provided the directives and components we needed. There is no routing at all.
With Angular 2 it looks like it is all or nothing. You declare a single root component and everything is rendered through that. This would be a big shift for us and I'd like to avoid changing how we are doing things on these public facing pages.
Is it possible at all to just use Angular 2 components as needed in static HTML pages or will we need to move to a single root element SPA design?
In a nutshell, what I'm asking is if it is possible to have a mix of static content with dynamic angular components sprinkled within, or must all angular components live within a single root element on the page?
So this is simpler than I originally thought. In the Angular 2 docs it has some specific wording around bootstrapping multiple apps.
Bootstrapping Multiple Applications
When working within a browser window, there are many singleton
resources: cookies, title, location, and others. Angular services that
represent these resources must likewise be shared across all Angular
applications that occupy the same browser window. For this reason,
Angular creates exactly one global platform object which stores all
shared services, and each angular application injector has the
platform injector as its parent.
Each application has its own private injector as well. When there are
multiple applications on a page, Angular treats each application
injector's services as private to that application.
So it seems clear that this is intended to be possible and that multiple apps share service resources which is what I would hope for.
I've done some trivial tests with multiple bootstrapped components and it works fine. One thing I have not yet tried is bootstrapping an Angular 2 attribute directive for use outside of Angular 2 components. I suspect that won't work and that bootstrap only works with Components and not Directives.
In terms of guidance, I would suggest that Angular 2 is not really designed for sprinkling behaviour throughout a static page and probably should not be used that way. Rather, while you may have multiple sections of your paged defined by multiple apps, that components should make up nearly all of the document/interface.
we simply bootstrapped the document element with a module that provided the directives and components we needed. There is no routing at all
That's exactly how I'm currently using Angular2. See the example at https://github.com/niczero/ng2-es5-file-upload/blob/master/demo/index.html -- some of my 'static' pages are generated by perl in the same way you are using ruby.
As an aside, being able to use your modules both ways is much easier if you embrace Universal Module Definitions
I have a site that is developed by multiple developers that has multiple pages. Each "page" initializes angular by calling angular.module(etc).
My question is, all pages share some modules, and some pages use specific modules. What is the best practice to achieve this? Do I trust that developers will insert the correct modules that will be needed across the site (i.e. Google Analytics) or do I create one call that is shared my all pages that loads ALL the modules. And is there a way to do both? Such as, initilize the modules that are needed across all the pages and then, load specific modules dynamically on their respective pages.
I would make one global module that is loaded by each individual app, much like modules like 'ngAnimate' are loaded... the global module could then initialize functionality common to all pages, such as Google analytics.
This requires some policing on all developers involved, but this is a good practice via code reviews, etc.
example page:
angular.module('individualPage', [
'globalModule',
'customPageModule'
]).config(
// etc
);
global module:
angular.module('globalModule', [
'googleAnalytics'
]).config(
// etc
);
I have a site that is developed by multiple developers that has multiple pages. Each "page" initializes angular by calling angular.module(etc).
My question is:
All pages share some modules, and some pages use specific modules. What is the best practice to achieve this?
I do not know the best practice when dealing with multiple pages.
IMHO, creating multiple pages is a BAD practice nowadays. I think of
web applications(SPAs) that have different views and states not web
sites with disjointed pages. So if you choose to go the
SPA(single page application) way, you can load all you core/common
modules before the application bootstraps. Views/pages that need
specific modules can lazy load them using something like
oclazyload.
Do I trust that developers will insert the correct modules that will be needed across the site (i.e. Google Analytics) or do I create one call that is shared my all pages that loads ALL the modules.
I can't say much about the question of trust as I do not know your
developers well enough. In general, developers are never to be
trusted, they will do anything that seems to work, high five
themselves and call it a day. The idea is to "Trust but verify", you
don't have to wire tap their phones or read their emails but never
ever take your eyes off the main git or svn repository. Anywhere, If
you were to use oclazyload as I suggested above for a SPA, you would
only need to worry about dynamically loading 'view/page' specific
modules which the developers can configure themselves.
And is there a way to do both? Such as, initilize the modules that are needed across all the pages and then, load specific modules dynamically on their respective pages.
Yes, yes, there is ... SPA approach that I have already outlined
above. I would also recommend using angular-ui-router for the
states and views approach. The idea is to design your application
whilst thinking of it as a desktop or mobile thick client that has
state transitions and so forth.
I have a site that is developed by multiple developers that has multiple pages.
Each "page" initialises angular by calling angular.module(etc).
My question is, all pages share some modules, and some pages use specific modules.
What is the best practice to achieve this?
Do I trust that developers will insert the correct modules that will be needed across the site (i.e. Google Analytics)
or do I create one call that is shared my all pages that loads ALL the modules.
And is there a way to do both?
Such as, initialise the modules that are needed across all the pages and then, load specific modules dynamically on their respective pages.
I would start off by defining what a page is.
Are you talking about a SPA or a more traditional setup a la client transitions between pages with a regular <a href="/page"> and
the server serves the client a piece of HTML?
If the latter is true, then I would urge you to reconsider your underlying approach to your Angular application.
The best (or rather, preferred) way of doing things would be to serve the client a single piece of HTML, and then
transition between pages (from now on I will refer to them as states), by using either ngRoute, angular router (2), or
better yet - ui-router.
For the remainder of my answer I am going to assume that you are in fact working with a SPA.
What is the best practice to achieve this?
As it stands, I would go out on a limb and say that there is no best practice defined for the case you present.
There are a ton of ways to do it, none of which have been officially recommended by the core development team / community standard as far as I'm concerned.
You could go with webpack-angularjs-lazyload, requirejs (angular-requirejs-seed), requirejs (angularAMD), SystemJS among others. Pick your poison of preference!
Do I trust that developers will insert the correct modules that will be needed across the site (i.e. Google Analytics)
or do I create one call that is shared my all pages that loads ALL the modules.
If code contained in an angular.module is required across the site, I would attach it to the main application module.
Such as:
/** Define core functionality that _is_ essential to the application running as expected **/
angular.module('core-module', [ 'route-definitions', 'http-interceptors', 'google-analytics' ]);
/** Inject the core functionality into a bundle module **/
angular.module('main-bundle-module', [ 'core-module' ]);
/** Bootstrap the bundle module as your application **/
angular.bootstrap(/* DOM element */, ['main-bundle-module']);
Now, whenever someone creates a new module for a specific state, they will need to inject said module into the main-bundle-module (barring lazy loaded modules).
As such, the core functionality will always be supplied and available, in your case Google Analytics. In a sense, you just tore down
the trust barrier.
Taking a step back, lets for a moment assume that you are not working with a SPA - and you are in fact re-initialising the
angular application on each page transition (bad move). How would you ensure that the required functionality is always present?
Decorating the angular.module method.
Note: This is not officially supported, be wary of what you are doing. Also it defeats the purpose of modularisation in my opinion, but I'll
showcase the way(s) of doing it.
You could go two ways here I reckon:
Kill the execution of JS if the required module is not a part of the developers module definition.
"Bad cop."
This would catch the 'untrusted developer' in his/her tracks during development, so as to ensure they are following the project standard.
Assist the 'untrusted developer' by automating the task of requiring the module.
"Good cop." (well, sort of...)
This would ensure that the required module is always present, albeit in every module.
"Good Cop"
(function(angular) {
// The always required module(s).
var ALWAYS_REQUIRED = ['cs.core'];
// Keep a reference to the original angular.module function.
var originalFn = angular.module;
// Keep track of registered modules.
var registered = {};
angular.module = function (name, dependencies, configFunction) {
var loaded;
// Ensure that we are always working with an array of dependencies.
dependencies = dependencies || [];
// If the module has not already been registered
if (!registered[name]) {
// Ensure that the required modules are available.
ALWAYS_REQUIRED.forEach(function (required) {
if (dependencies.indexOf(required) === -1) {
dependencies.push(required);
}
});
// Register the module and store it in the registered object for future reference.
loaded = registered[name] = original(name, dependencies, configFunction);
} else {
// Do not re-register the module, simply load it as per 'angular.module('name_of_module')';
loaded = original(name);
}
// Return the loaded module.
return loaded;
};
})(angular);
"Bad Cop"
(function(angular) {
var ALWAYS_REQUIRED = ['cs.core'];
var originalFn = angular.module;
angular.module = function (name, dependencies, configFunction) {
ALWAYS_REQUIRED.forEach(function (required) {
if (dependencies.indexOf(required) === -1) {
throw new Error('You need to add ' + required + ' to ' + name + '\'s module dependencies!');
}
});
return originalFn(name, dependencies, configFunction);
};
})(angular);
That's two ways of killing the trust issue, but in doing so we've introduced code that;
Is not very pretty.
Is definitely not very well tested / battle proven.
Kills modularisation to boot.
And is there a way to do both?
Such as, initialise the modules that are needed across all the pages and then, load specific modules dynamically on their respective pages.
I would say the best way to do so is to:
Take the steps necessary to convert to a SPA.
Write some documentation for all your developers so as to bring them up to speed on the requirements of the project.
Create a standalone module containing the required core functionality and attach it to your ng-app/angular.bootstrap module.
Get ui-router, ui-router-extras and ocLazyLoad to allow for lazy loaded module/state/component definitions.
Have a look at some of the following links for inspiration/ideas on what fits your specific project:
ocLazyLoad-SystemJS-Router by #lookfirst
ng-jspm-seed#futureStateConfig by #kasperlewau
ocLazyLoad#with-your-router
ocLazyLoad+requirejs plunker
webpack vs browserify #stackoverflow
angular + webpack slides
tl;dr
Convert to a SPA.
Bootstrap the application with core functionality supplied.
Write some documentation for untrusted developers.
Better yet, build trust. :)
Lazy load state-specific modules when needed.
You can try browserify to load and build your javascript in single file.
With this you can easy minify the javascript code, and also you can load nodejs modules like events and more, but this is not your question about.
We do a modular application where the UI is divided in components/modules like billing area, staff management, real time charts, shipment etc... The customer pays for this component/module and only the modules he paid for shall be loaded on client side. I name these paid modules "main modules" on client side because every main module is route/button to sub content where user with different claims can do different things.
What I would like to do now is before angular is initialized I would like to manually create the modules basing on the array of licensed module names. Those modules who are not licensed are not created.
Here I have an understanding problem and can not find any similar case in google.
1.) How can I tell angularjs to load a specific module with all its attached controllers/services and their depending modules?
2.) What happens with the common javascript includes which will cause an immediate creation of the angularjs modules?
User #mpm put me on the right track. Its the best if all the files belonging to a angular module are copied over to the index.html before the body tag before the Index.html is initially sent to the client side. That way the client does not know about how the modules are loaded. It just gets the modules... Only the server knows and is doing still more stuff about the modules to be licenced like loading only the module depending endpoints/ApiController`s.
To second this answer as a recommend approach, you can watch this video:
https://www.youtube.com/watch?v=62RvRQuMVyg#t=486
from the angular conference where they recommend the same approach :-)
I'm new on angluarjs and trying to build an example-application.
This application is divided into 3 parts/sections:
A.) map
B.) "received"-area
C.) "send"-area
Every section has its own layout/view-area, not visible at the same time.
In part B.) you can load information from server by click or automatically, which will be displayed in part "B.)" as text and in section "A.)" as map-marker.
Additionally you can click inside section "A.)" to set a new marker.
In section "C.)" there is a send button to take the new marker from "A.)" in order to send this to the server.
Currently: all of the sections (A,B,C) are angular modules/own apps.
But I don't know, if that is the right way/best practice.
An other way could be a single module for the whole page an 3 controllers (A,B,C) which handle the logic for sections A,B and C.
What is the right way in angularjs?
From your description, I recommend designing it as a single AngularJS app with separate controllers for each view. It sounds like you would benefit from using an angular service to handle the client-side business logic and cache any shared data/models that could be used by the views. It is a best-practice in Angular to keep the controllers pretty lean and focused just on the view setup/binding and orchestrating the access to the services.
After searching the way to get some inspiration, i decided to realize the following think:
For all the self-made code, I use one module for the whole application and for all the external things, bundled with external plugins and services, I take a different module. This means: pne module for each "service-plugin bundle" (like google API & angular-google-maps plugin)
So I can switch the module, if the external service does not work, etc.
Looking at my example in the question this means:
Application part A: the map and all the map-specific things (set new marker, draw circle, etc) are insight a map-module. If I decide to use open street map instead of google maps i will plug in an new maps module
Application part A and B: this is my "main" app module with different controllers.
I am starting a new project with the idea of moving some logic to client side.
I was looking in Backbone, and later in Marionette. Looks like it is a very good library which extends backbone to make it easier to create an application.
However, I couldn't find in any place a good document explaining the architecture and philosophy behind modules in Marionette.
My question is, although it is quite wide, how should I organize my code? What is the idea behind Module? What should it represent?
My reference is the MarionetteJS TODO example.
Thanks!
I do not want to write many texts I will just demonstrate two folders structures I like.
Group by independent modules (<3)
src
application
router.js // router here or for each module
main.js // app entry point
profile
collections
models
views
templates
profile.js // module entry point
news
collections
models
views
templates
news // module entry point
Group by Backbone types
src
collections
profile
news
models
profile
news
modules
profile.js // module entry point
news.js // module entry point
views
profile
news
templates
profile
news
router.js // router
main.js // app entry point