Angular2: Module architecture and example seed project

Thomas Rundle
6 min readNov 4, 2016

--

I will write several Angular 2 tutorials based on Angular 2 projects I’ve developed. The intended audience is developers who have already had a thorough introduction to Angular 2 and are looking to master concepts while building robust, reusable modules that can be leveraged for future billable projects.

Perhaps like me, there are others who have been through most of the Angular team’s documentation and even some of the source, but are still asking “Just how well do I know this? Am I ready to build enterprise applications with it?”

Building a large, feature rich project is the only way to find out. I start small by building a seed project based on the Quickstart Guide on angular.io.

Of course, there are several ways to setup a new Angular 2 project. You may prefer webpack over SystemJS. You may like the Angular CLI. I want my tutorials to serve as an extension of the excellent work the Angular team has done on angular.io. As such, I will use their Quickstart Guide and follow all architectural recommendations included in their documentation.

If you are new to Angular 2, I highly recommend the Angular Docs, Angular 2 Development with TypeScript (early access), and Victor Savkin’s blog. These have been my go-to resources for the past several months.

This project establishes the following module architecture based on guidelines in the documentation for NgModule.

Create the seed project

You can also download the seed project from my GitHub repo.

  1. Follow the Quickstart Guide.

Once you’ve followed these steps, your working directory will look like this:

For simple styling, load Bootstrap into index.html using the CDN provided at getbootstrap.com.

<!-- Bootstrap compiled and minified CSS -->
<link rel=”stylesheet” href=”https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

2. Setup CoreModule.

The CoreModule is where we include application wide components and services. We import this module into AppModule and nowhere else. Components included statically on all your views, such as app navigation, are ideal candidates for inclusion in the CoreModule.

Likewise, services that will be utilized by the entire app, such as a UserService storing user profiles and handling authentication, belong in the CoreModule.

Create the core folder and put three new files inside it:

// core/core.module.ts
import { NgModule } from ‘@angular/core’;
import { CommonModule } from ‘@angular/common’;
import { NavbarComponent } from ‘./navbar.component’;@NgModule({
imports: [ CommonModule ],
declarations: [ NavbarComponent ],
exports: [ NavbarComponent ],
providers: []
})
export class CoreModule { }

The CoreModule declares and exports the NavbarComponent. This allows the <ct-navbar> selector to be placed on the AppComponent template.

// core/navbar.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'ct-navbar',
templateUrl: 'app/core/navbar.component.html'
})
export class NavbarComponent { }

The Angular docs recommend adding a prefix to the selectors on your component to future-proof your application against possible conflicts with future HTML specifications. The prefix I use happens to be “ct”. Do not use “ng” as a prefix, because this prefix should be reserved for Angular built-in components.

// core/navbar.component.html
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand">Project Manager</a>
</div>
<ul class="nav navbar-nav">
<li><a>Link 1</a></li>
<li><a>Link 2</a></li>
</ul>
</div>
</nav>

Now, update the AppModule to import the CoreModule and insert
<ct-navbar> into the the AppComponent template.

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CoreModule } from './core/core.module';import { AppComponent } from './app.component';
@NgModule({
imports: [
BrowserModule,
CoreModule
],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }

I prefer separate HTML files rather than inline templates in most cases. I adjust the AppComponent accordingly.

// app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html'
})
export class AppComponent { }

Insert the NavbarComponent selector into the AppComponent template.

// app.component.html
<ct-navbar></ct-navbar>

The running application now looks like:

This is a good start for the CoreModule. Now lets work on the SharedModule.

3. Setup SharedModule.

The SharedModule contains components that will be reused in two or more feature modules. We will setup the SharedModule for this seed project with one component. A TableLayoutComponent is just the kind of component that is likely to be reused in many parts of the application.

Create the shared folder and create three files inside it.

// shared/shared.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TableLayoutComponent } from './table-layout.component';@NgModule({
imports: [ CommonModule ],
declarations: [ TableLayoutComponent ],
exports: [
CommonModule,
TableLayoutComponent
]
})
export class SharedModule { }

By importing and then re-exporting CommonModule, we’ll save ourselves from needing to import CommonModule into any feature modules that import this SharedModule. We declare and export TableLayoutComponent. This component contains a template we wish to make available to several modules later on.

// shared/table-layout.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'ct-table',
templateUrl: 'app/shared/table-layout.component.html'
})
export class TableLayoutComponent { }

The template contains an example 3 x 3 table with Bootstrap styling.

// shared/table-layout.component.html
<table class="table">
<caption>Table</caption>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Some value</td>
<td>Some value</td>
<td>Some value</td>
</tr>
<tr>
<td>Some value</td>
<td>Some value</td>
<td>Some value</td>
</tr>
<tr>
<td>Some value</td>
<td>Some value</td>
<td>Some value</td>
</tr>
</tbody>
</table>

That’s it for the SharedModule for now. To make use of it, we need a feature module. Creating this feature module is the last step in this article.

Note: For this example template to be useful, the table needs to be dynamically constructed based on data sent to it. In a follow up article, I will demonstrate how to build out this starter component for a dynamic table layout.

4. Leverage the SharedModule within a feature module.

The rest of the Angular 2 application will be contained in feature modules. The Angular docs describe feature modules as collections of related functionality that are imported into the root module.

As an example, we’ll create a feature called ProjectCenterModule.

Create a project-center folder with three new files.

// project-center/project-center.module.ts
import { NgModule } from '@angular/core';
import { SharedModule } from '../shared/shared.module';import { ProjectCenterComponent } from './project-center.component';@NgModule({
imports: [ SharedModule ],
declarations: [ ProjectCenterComponent ],
providers: [],
exports: [ ProjectCenterComponent ]
})
export class ProjectCenterModule { }

Notice that we imported the SharedModule into our ProjectCenterModule.

// project-center/project-center.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'ct-project-center',
templateUrl: 'app/project-center/project-center.component.html'
})
export class ProjectCenterComponent {
title: string = 'Project Center';
}

The template implements the <ct-table> selector made available through the SharedModule.

// project-center/project-center.component.html
<div class="container-fluid">
<div class="page-header">
<h1>{{ title }}</h1>
</div>
<ct-table></ct-table>
</div>

Before we run the app, AppModule needs to be updated to import ProjectCenterModule.

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CoreModule } from './core/core.module';
import { ProjectCenterModule } from './project-center/project-center.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [
BrowserModule,
CoreModule,
ProjectCenterModule
],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }

And insert the <ct-project-center> selector into the AppComponent template.

// app.component.html
<ct-navbar></ct-navbar>
<ct-project-center></ct-project-center>

Run the app and this is what you’ll see.

Not terribly interesting, but it is a good baseline from where we can explore more advanced topics.

--

--

Thomas Rundle

Web developer, management consultant, and NASA enthusiast. Twitter: @thomas_rundle. Github: https://github.com/conduitl