The Modern Application Stack – Part 4: Building a Client UI Using Angular 2 (formerly AngularJS) & TypeScript
Introduction
This is the fourth in a series of blog posts examining technologies such as Angular that are driving the development of modern web and mobile applications.
"Modern Application Stack – Part 1: Introducing The MEAN Stack" introduced the technologies making up the MEAN (MongoDB, Express, Angular, Node.js) and MERN (MongoDB, Express, React, Node.js) Stacks, why you might want to use them, and how to combine them to build your web application (or your native mobile or desktop app).
The remainder of the series is focussed on working through the end to end steps of building a real (albeit simple) application. – MongoPop. Part 2: Using MongoDB With Node.js created an environment where we could work with a MongoDB database from Node.js; it also created a simplified interface to the MongoDB Node.js Driver. Part 3: Building a REST API with Express.js built on Part 2 by using Express.js to add a REST API which will be used by the clients that we implement in the final posts.
This post demonstrates how to use Angular 2 (the evolution of Angular.js) to implement a remote web-app client for the Mongopop application.
Angular 2 (recap)
Angular, originally created and maintained by Google, runs your JavaScript code within the user's web browsers to implement a reactive user interface (UI). A reactive UI gives the user immediate feedback as they give their input (in contrast to static web forms where you enter all of your data, hit "Submit" and wait.

Version 1 of Angular was called AngularJS but it was shortened to Angular in Angular 2 after it was completely rewritten in Typescript (a superset of JavaScript) – Typescript is now also the recommended language for Angular apps to use.
You implement your application front-end as a set of components – each of which consists of your JavaScript (Typescript) code and an HTML template that includes hooks to execute and use the results from your Typescript functions. Complex application front-ends can be crafted from many simple (optionally nested) components.
Angular application code can also be executed on the back-end server rather than in a browser, or as a native desktop or mobile application.
Downloading, running, and using the Mongopop application
The Angular client code is included as part if the Mongopop package installed in Part 2: Using MongoDB With Node.js.
The back-end application should be run in the same way as in parts 2 & 3. The client software needs to be transpiled from Typescript to JavaScript – the client software running in a remote browser can then download the JavaScript files and execute them.
The existing package.json
file includes a script for transpiling the Angular 2 code:
"scripts": {
 ...
 "tsc:w": "cd public && npm run tsc:w",
 ... 
},

That tsc:w
delegates the work to a script of the same name defined in public/package.json
;
"scripts": {
 ...
 "tsc:w": "tsc -w",
 ... 
},

tsc -w
continually monitors the client app's Typescript files and reruns the transpilation every time they are edited.
To start the continual transpilation of the Angular 2 code:
npm run tsc:w

Component architecture of the Mongopop Angular UI
Angular applications (both AngularJS and Angular2) are built from one or more, nested components – Mongopop is no exception:
The main component (AppComponent)
contains the HTML and logic for connecting to the database and orchestrating its sub-components. Part of the definition of AppComponent
is meta data/decoration to indicate that it should be loaded at the point that a my-app
element (<my-app></my-app>
) appears in the index.html
file (once the component is running, its output replaces whatever holding content sits between <my-app>
and </my-app>
). AppComponent
is implemented by:
- A Typescript file containing the
AppComponent
class (including the data members, initialization code, and member functions - A HTML file containing
- HTML layout
- Rendering of data members
- Elements to be populated by sub-components
- Data members to be passed down for use by sub-components
- Logic (e.g. what to do when the user changes the value in a form)
- (Optionally) a CSS file to customise the appearance of the rendered content
Mongopop is a reasonably flat application with only one layer of sub-components below AppComponent
, but more complex applications may nest deeper.
Changes to a data value by a parent component will automatically be propagated to a child – it's best practice to have data flow in this direction as much as possible. If a data value is changed by a child and the parent (either directly or as a proxy for one of its other child components) needs to know of the change, then the child triggers an event. That event is processed by a handler registered by the parent – the parent may then explicitly act on the change, but even if it does nothing explicit, the change flows to the other child components.
This table details what data is passed from AppComponent
down to each of its children and what data change events are sent back up to AppComponent
(and from there, back down to the other children):
Child component | Data passed down | Data changes passed back up |
---|---|---|
AddComponent |
Data service | Collection name |
Collection name | ||
Mockaroo URL | ||
CountComponent |
Data service | Collection name |
Collection name | ||
UpdateComponent |
Data service | Collection name |
Collection name | ||
SampleComponent |
Data service | Collection name |
Collection name | Existence of sample data |
What are all of these files?
To recap, the files and folders covered earlier in this series:
package.json
: Instructs the Node.js package manager (npm
) what it needs to do; including which dependency packages should be installednode_modues
: Directory wherenpm
will install packagesnode_modues/mongodb
: The MongoDB driver for Node.jsnode_modues/mongodb-core
: Low-level MongoDB driver library; available for framework developers (application developers should avoid using it directly)javascripts/db.js
: A JavaScript module we've created for use by our Node.js apps (in this series, it will be Express) to access MongoDB; this module in turn uses the MongoDB Node.js driver.config.js
: Contains the application–specific configuration optionsbin/www
: The script that starts an Express application; this is invoked by thenpm start
script within thepackage.json
file. Starts the HTTP server, pointing it to theapp
module inapp.js
app.js
: Defines the main back-end application module (app
). Configures:- That the application will be run by Express
- Which routes there will be & where they are located in the file system (
routes
directory) - What view engine to use (Jade in this case)
- Where to find the views to be used by the view engine (
views
directory) - What middleware to use (e.g. to parse the JSON received in requests)
- Where the static files (which can be read by the remote client) are located (
public
directory) - Error handler for queries sent to an undefined route
views
: Directory containing the templates that will be used by the Jade view engine to create the HTML for any pages generated by the Express application (for this application, this is just the error page that's used in cases such as mistyped routes ("404 Page not found"))routes
: Directory containing one JavaScript file for each Express routeroutes/pop.js
: Contains the Express application for the/pop
route; this is the implementation of the Mongopop REST API. This defines methods for all of the supported route paths.
public
: Contains all of the static files that must be accessible by a remote client (e.g., our Angular to React apps).
Now for the new files that implement the Angular client (note that because it must be downloaded by a remote browser, it is stored under the public
folder):
public/package.json
: Instructs the Node.js package manager (npm
) what it needs to do; including which dependency packages should be installed (i.e. the same as/package.json
but this is for the Angular client app)public/index.html
: Entry point for the application; served up when browsing tohttp://<backend-server>/
. Importspublic/system.config.js
public/system.config.js
: Configuration information for the Angular client app; in particular defining the remainder of the directories and files:public/app
: Source files for the client application – including the Typescript files (and the transpiled JavaScript files) together the HTML and any custom CSS files. Combined, these define the Angular components.public/app/main.ts
: Entry point for the Angular app. Bootstrapspublic/app/app.module.ts
public/app/app.module.ts
: Imports required modules, declares the application components and any services. Declares which component to bootstrap (AppComponent
which is implemented inpublic/app/app.component.*
)public/app/app.component.html
: HTML template for the top-level component. Includes elements that are replaced by sub-componentspublic/app/app.component.ts
: Implements theAppComponent
class for the top-level componentpublic/app/X.component.html
: HTML template for sub-component _X_public/app/X.component.ts
: Implements the class for sub-component _X_AddDocsRequest.ts
,ClientConfig.ts
,CountDocsRequest.ts
,MongoResult.ts
,MongoReadResult.ts
,SampleDocsRequest.ts
, &UpdateDocsRequest.ts
: Classes that match the request parameters and response formats of the REST API that's used to access the back-enddata.service.ts
: Service used to access the back-end REST API (mostly used to access the database)X.js*
& *X.js.map
: Files which are generated by the transpilation of the Typescript files.
public/node-modules
: Node.js modules used by the Angular app (as opposed to the Express, server-side Node.js modules)public/styles.css
: CSS style sheet (imported bypublic/index.html)
– applies to all content in the home page, not just content added by the componentspublic/stylesheets/styles.css
: CSS style sheet (imported bypublic/app/app.component.ts
and the other components) – note that each component could have their own, specialized style sheet instead
"Boilerplate" files and how they get invoked
This is an imposing number of new files and this is one of the reasons that Angular is often viewed as the more complex layer in the application stack. One of the frustrations for many developers, is the number of files that need to be created and edited on the client side before your first line of component/application code is executed. The good news is that there is a consistent pattern and so it's reasonable to fork you app from an existing project – the Mongopop app can be cloned from GitHub or, the Angular QuickStart can be used as your starting point.
As a reminder, here is the relationship between these common files (and our application-specific components):
Contents of the "boilerplate" files
This section includes the contents for each of the non-component files and then remarks on some of the key points.
public/package.json
{
 "name": "MongoPop",
 "version": "0.1.1",
 "description": "Mongopop client - add data sets and run traffic on MongoDB",
 "scripts": {
 "start": "tsc && concurrently \"tsc -w\" ",
 "postinstall": "typings install",
 "tsc": "tsc",
 "tsc:w": "tsc -w",
 "typings": "typings"
 },
 "keywords": [],
 "author": "Andrew Morgan",
 "license": "ISC",
 "dependencies": {
 "@angular/common": "2.0.0-rc.6",
 "@angular/compiler": "2.0.0-rc.6",
 "@angular/core": "2.0.0-rc.6",
 "@angular/forms": "2.0.0-rc.6",
 "@angular/http": "2.0.0-rc.6",
 "@angular/platform-browser": "2.0.0-rc.6",
 "@angular/platform-browser-dynamic": "2.0.0-rc.6",
 "@angular/router": "3.0.0-rc.2",
 "@angular/upgrade": "2.0.0-rc.6",
 "bootstrap": "^3.3.6",
 "core-js": "^2.4.1",
 "gulp": "^3.9.1",
 "reflect-metadata": "^0.1.3",
 "rx": "^4.1.0",
 "rxjs": "5.0.0-beta.11",
 "systemjs": "0.19.27",
 "zone.js": "^0.6.17"
 },
 "devDependencies": {
 "concurrently": "^2.2.0",
 "typescript": "^1.8.10",
 "typings": "^1.0.4",
 "canonical-path": "0.0.2",
 "http-server": "^0.9.0",
 "lodash": "^4.11.1",
 "rimraf": "^2.5.2"
 },
 "repository": {}
}
The scripts
section defines what npm
should do when you type npm run <command-name>
from the command line. Of most interest is the tsc:w
script – this is how the transpiler is launched. After transpiling all of the .ts
Typescript files, it watches them for changes – retranspiling as needed.
Note that the dependencies
are for this Angular client. They will be installed in public/node_modules
when npm install
is run (for Mongopop, this is done automatically when building the full project ).
public/index.html
<!DOCTYPE html>
<html>
 <!--
 This is the file that will be served to anyone browsing to http://server-running-mongopop-back-end/
 Then, by loading 'systemjs.config.js', Angular2 will replace the "my-app" element with the Mongopop
 client application.
 -->
 <head>
 <title>MongoPop</title>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <link rel="stylesheet" href="styles.css">
<pre><code><!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>

<script src="node_modules/zone.js/dist/zone.min.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>

<script src="systemjs.config.js"></script>
<script>
 System.import('app').catch(function(err){ console.error(err); });
</script>