When approaching Angular 2 initially, it is useful to have an understanding of an application structure that is torn down to the bare metal. In the case of a minimum viable application, it will consist of a single component. Since this is a chapter on application organization, it isn't so much about what that component will look like, but rather how to take the TypeScript component definition and actually get it to render in a web page.
The code, links, and a live example of this are available at .
This recipe assumes you have completed all the steps given in the Composing configuration files for a minimum viable Angular 2 application recipe. The npm
module installation should succeed with no errors:
npm install
The simplest place to start is the core application component.
Implement a component inside a new app/
directory as follows; there should be no surprises:
[app/app.component.ts] import {Component} from '@angular/core'; @Component({ selector: 'app-root', template: '<h1>AppComponent template!</h1>' }) export class AppComponent {}
This is about as simple a component can possibly get. Once this is successfully rendered in the client, this component should just be a big line of text.
Next, you need to define the NgModule
that will be associated with this component. Create another file in the app/
directory, app.module.ts
, and have it match the following:
[app/app.module.ts] import {NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {AppComponent} from './app.component'; @NgModule({ imports: [BrowserModule], declarations: [AppComponent], bootstrap: [AppComponent] }) export class AppModule {}
There's a bit more going on here:
imports
specifies the modules whose exported directives/pipes should be available to this module.Importing BrowserModule
gives you access to core directives such as NgIf
and also specifies the type of renderer, event management, and document type. If your application is rendering in a web browser, this module gives you the tools you need to do this.
declarations
specifies which directives/pipes are being exported by this module. In this case, AppComponent
is the sole export.bootstrap
specifies which components should be bootstrapped when this module is bootstrapped. More specifically, components listed here will be designated for rendering within this module. AppComponent
needs to be bootstrapped and rendered somewhere, and this is where this specification will occur.This completes the module definition. At this point, you have successfully linked the component to its module, but this module isn't being bootstrapped anywhere or even included.
You'll change this next with main.ts
, the top-level TypeScript file:
[app/main.ts] import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {AppModule} from './app.module'; platformBrowserDynamic().bootstrapModule(AppModule);
This file defines the NgModule
decorator that will be used for AppComponent
. Inside it, you specify that the module must import BrowserModule
.
Recall that Angular 2 is designed to be platform-independent. More specifically, it strives to allow you to write code that might not necessarily run on a conventional web browser. In this case, you are targeting a standard web browser, so importing BrowserModule
from the platformBrowser
target is the way in which you can inform the application of this. If you were targeting a separate platform, you would select a different platform to import into your root application component.
This NgModule
declaration also specifies that AppComponent
exists and should be bootstrapped.
Bootstrapping is how you kick off your Angular 2 application, but it has a very specific definition. Invoking bootstrap()
tells Angular to mount the specified application component onto DOM elements identified by the component's selector. This kicks off the initial round of change detection and its side effects, which will complete the component initialization.
Since you've declared that this module will bootstrap AppComponent
when it is bootstrapped, this module will in turn be the one bootstrapped from the top-level TypeScript file. Angular 2 pushes for this convention as a main.ts
file:
[app/main.ts] import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {AppModule} from './app.module'; platformBrowserDynamic().bootstrapModule(AppModule);
The platformBrowserDynamic
method returns a platform object that exposes the bootstrapModule
method. It configures your application to be bootstrapped with Angular 2's just-in-time (JIT) compiler.
For now, the details of why you are specifying just-in-time compilation aren't important. It's enough to know that JIT compilation is a simpler version (as opposed to ahead-of-time compilation) in Angular 2's offerings.
Finally, you need to build an HTML file that is capable of bundling together all these compiled files and kicking off the application initialization. Begin with the following:
[index.html] <html> <head> <title>Angular 2 Minimum Viable Application</title> <script src="node_modules/zone.js/dist/zone.js"> </script> <script src="node_modules/reflect-metadata/Reflect.js"> </script> <script src="node_modules/systemjs/dist/system.src.js"> </script> </head> <body> <app-root></app-root> </body> </html>
Most of this so far should be expected. ZoneJS and Reflect are Angular 2 dependencies. The module loader you'll use is SystemJS. <app-root>
is the element that AppComponent
will render inside.
Next, SystemJS needs to be configured to understand how to import module files and how to connect modules from being imported inside other modules. In other words, it needs to be given a file to begin with and a directory of mappings for dependencies of that main file. This can be accomplished with System.config()
and System.import()
, which are methods exposed on the global System
object:
[index.html] <html> <head> <title>Angular 2 Minimum Viable Application</title> <script src="node_modules/zone.js/dist/zone.js"> </script> <script src="node_modules/reflect-metadata/Reflect.js"> </script> <script src="node_modules/systemjs/dist/system.src.js"> </script> <script> System.config({ paths: { 'ng:': 'node_modules/@angular/' }, map: { '@angular/core': 'ng:core/bundles/core.umd.js', '@angular/common': 'ng:common/bundles/common.umd.js', '@angular/compiler': 'ng:compiler/bundles/compiler.umd.js', '@angular/platform-browser': 'ng:platform-browser/bundles/platform-browser.umd.js', '@angular/platform-browser-dynamic': 'ng:platform-browser-dynamic/bundles/platform-browser- dynamic.umd.js', 'rxjs': 'node_modules/rxjs' }, packages: { app: { main: './main.js' }, rxjs: { defaultExtension: 'js' } } }); System.import('app'); </script> </head> <body> <app-root></app-root> </body> </html>
System.config()
specifies how SystemJS should handle the files passed to it.
paths
property specifies an alias to shorten the path's inside map
. It acts as a simple find and replace function, so any found instances of ng:
are replaced with node_modules/@angular/
.map
property specifies how SystemJS should resolve the module imports that you have not explicitly defined. Here, this takes the form of five core Angular modules and the RxJS library.packages
property specifies the targets that will be imported by this property and the files they need to map to.For example, the app
property will be used when a module imports app
, and inside SystemJS, this will map to main.js
. Similarly, when a module requires an RxJS module, such as Subject
, SystemJS will take the rxjs/Subject
import path, recognize that defaultExtension
is specified as js
, map the module to its file representation node_modules/rxjs/Subject.js
, and import it.