Home Angular2 from Scratch - Getting to know Angular2
Post
Cancel

Angular2 from Scratch - Getting to know Angular2

In this post, we are going to focus on some pretty basic stuff, like setting up the application and getting it working. Posts will become more advanced during the series progress. Feedback is always appreciated, so please, if you have any thoughts on how this and future posts can be improved, leave your comments below.

Who is this article for

If you are a beginner on Angular2, if the framework is something new for you and you wish to learn more about it, this is the article for you. We are going to setup Angular2 with TypeScript on VSCode, getting a very basic hello world application.

Article is updated to follow latest Angular2 final version.

Prerequisites

Regarding tooling, you will need to have installed NodeJS, NPM, VSCode and TypeScript.

In order to better understand the concepts on Angular2, a minimal knowledge on JavaScript and TypeScript is required.

So, make sure you have NodeJS installed on your machine first. If not, find it here.

Then, make sure you have NPM installed. NPM ships with NodeJS, so if you have it, then you have NPM as well in your machine. Make sure you got the latest by running the following command in a CMD window:

npm install npm -g

Finally make sure you have TypeScript...

npm install typescript -g

... and VSCode installed.

The Angular2 movement

Angular2 (yes, no AngularJS 2, just Angular2) is the new kid in the block, in SPA frameworks. It comes sexiest than ever, faster, powerful, cleaner, it is really the dreamland for a web developer. It comes with support in ES6, TypeScript and Dart.

Careful though. This is a framework that is designed (until this time of writing at least) to be a solely SPA framework, so if you are considering an SPA application, yes this is the way to go. I mean, really, give it a try, you are going to love it.
If not, you are probably planning to span the framework across pages, having a non-SPA application, so this framework is not meant for your. This could be done with the previous AngularJS, or Backbone.js, to have the app module, lets say in AngularJS, and use it in different pages to register controllers, which doesn't use the routing feature though. I don't find a very good reason to do so, but I am here to warn you.
This is a reddit discussion on the matter, where some hacks are introduced, but I wouldn't recommend that. If the guys at Google wanted you to do so, they would have included it, so try to stick around with the framework.

What's new comparing to AngularJS?

This will be a brief introduction in Angular2 vs AngularJS, as this can be a very lengthy section, which fits on its own article.

First, performance. Angular2 has made significant refactoring on the framework, compared to the previous version, such as killing off watchers and digest cycles. From this you can understand how much pain you are saved from, because, yes, lets admit it, it was pain, which needed extra consideration as well as performance tuning. If you are not familiar with tuning techniques on AngularJS, check this amazing presentation by Todd Motto, which I had the pleasure to watch it live (streaming). Thanks Todd!

Next, tooling. Angular2 is build on top of TypeScript, so you can leverage its great power to build unique, clean and robust code. Your code is modularized, truly this time, with individual entities, such as components, services, directives, ready to be consumed as modules. You declare your modules, export them to make them visible to the application, and of course import them where you need them. Boom! Code is ready to be used. TypeScipt supports many module loading techniques, such as CommonJS, AMD and others. Check the modules section on TypeScript documentation for more on the subject, as well as this incredible article from Addy Osmani on Modular JavaScript.
IDE's today have very good support on Angular2, like VSCode, Atom, Sublime, Webstorm, etc. You must be wondering why I didn't include Visual Studio 2015. Read on Tips section below.

Also, universal apps are possible through Angular2. The framework is not focused on Web Applications, like the previous one, which was designed only to support responsive web applications, instead it has a wide range of devices support, as well as creating mobile applications, with NativeScript and ReactNative.

Last, but not least in this quick brief intro to Angular2, is forget about controllers, forget about factories, providers, directives, as everything is a component now. Yes, Angular2 is following the steps of React on componetizing the UI and it is doing a great job. Forget setting a controller and working with $scope, no more. Now you have the power to construct your designs, extracting small components on functionality throughout your UI, something that was not that straightforward in the previous framework, or was too cumbersome with Backbone.js and Marionette.js (it was kinda similar in mindset).

Walkthrough

Let's first show the structure we are going to create and then move on with the walkthrough.

|-css
|----style.css
|-src
|----app
|--------home.component.css
|--------home.component.html
|--------home.component.ts
|--------app.component.cs
|--------app.component.html
|--------app.component.ts
|--------app.module.ts
|--------main.ts
|-index.html
|-package.json
|-system-config.js
|-tsconfig.json
|-typings.json

Pretty basic setup, a package.json to fetch all NPM modules we need, a tsconfig.json to provide instructions to the TypeScript compiler, a typings.json to provide some TypeScript definitions, a system-config.js to configure SystemJS module loader, an index.html as the default document of the application and in the src folder we have all the Angular2 specific code. In css folder we just have some global CSS styles.

Main.ts is responsible for bootstraping the Angular2 application by loading the application module, which is the AppModule class. This loads all the underlying components as well as the root AppComponent.
App.component.ts is the main component, which hosts all components in the Angular2 application, so think about it as a master component, the root of all components. These three, app.module.ts, main.ts and app.component.ts are the minimum requirements in every Angular2 application you build.

home.component.ts will be just a hello world component for the sake of this walkthrough. As you can see, all related to component resources (*.css, *.html) are component specific, so we have component specific CSS and HTML code, which serves as its template.

Make sure to add all the above folder and files, and we are going to talk about their implementation in the next sections.

Let's go through all the necessary steps for creating this basic application.

VSCode

Go to your file system and create a new folder, for the application. Name it Angular2FromScratch.

Open VSCode now, go to menu File > Open Folder and navigate to the folder you just created.

package.json

We need to install all the required dependencies for the application. On VSCode press Ctrl + Shift + C to open a Command Prompt Window. There, type npm init to create the package.json. Answer to the questionnaire and when its finished, paste the following code:

"dependencies": {
    "@angular/common": "2.0.0-rc.6",
    "@angular/compiler": "2.0.0-rc.6",
    "@angular/core": "2.0.0-rc.6",
    "@angular/platform-browser": "2.0.0-rc.6",
    "@angular/platform-browser-dynamic": "2.0.0-rc.6",
    "systemjs": "0.19.27",
    "core-js": "^2.4.0",
    "reflect-metadata": "^0.1.3",
    "zone.js": "^0.6.17",
    "rxjs": "5.0.0-beta.11",
    "bootstrap": "^3.3.6"
  },
  "devDependencies": {
    "lite-server": "^2.2.2",
    "concurrently": "^2.2.0",
    "typescript": "^1.8.10",
    "typings": "^1.3.2"
  },

Just be sure to overwrite the scripts section with the one above, so you can have the web-server ready to run, as well as compiling your TypeScript code through the commands. The tsc command compiles the TypeScript files in your application, whereas the tsc -w command compiles them and watches for changes, recompiling if needed.
The lite-server command kicks-off the lite web server, running and hosting the application.

So, regarding the libraries, these are the minimum required for this simple application. Angular2 has packages for different framework features, so everything is modular, we have a core package, with core functionality, like Components, we have an Http package to provide communication through the network by the use of HTTP providers, etc.

tsconfig.json

Next is the tsconfig.json to set, in order to provide some compiler instructions. Paste the following code in this file.

{
    "compilerOptions": {
        "target": "es6",
        "module": "commonjs",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": false,
        "noImplicitAny": false
    },
    "exclude": [
        "node_modules"
    ]
}

We instruct the compiler the following:

  • Use ES6 as ECMAScript target version.
  • Use commonjs as module code generation technique.
  • Use node as module resolution strategy.
  • Generate source maps.
  • Emit design-type metadata for decorated declarations in source.
  • Use the expirimental decorators.
  • Remove comments from the generated .js files.
  • Warn on expressions or declarations that use any

Lastly, we exclude certain directories from the compilation process.

typings.json

Paste the following code in typings.json.

{
    "globalDependencies": {
        "core-js": "registry:dt/core-js#0.0.0+20160317120654",
        "node": "registry:dt/node#4.0.0+20160509154515"
    }
}

Or alternatively open the terminal (Ctrl+`) and type the following:

typings install --save --global dt~core-js

typings install --save --global dt~node

Install dependencies

Now, go to the CMD you have open (if not, press Ctrl + Shift + c) and type npm install. This will install all the dependencies and devDependencies you have on package.json.

When this operation is completed, we can proceed in creating the index.html, the systemjs-config.js and the rest Angular2 code.

index.html

<!DOCTYPE>
<html lang="en">

<head>
    <meta charset="utf-8" />

    <!-- for ie to work with edge simulation -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />

    <!-- Fixes viewport zoom on smaller devices -->
    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <title>Angular2 From Scratch</title>

    <link rel="stylesheet" type="text/css" href="css/styles.css" />

    <!--Dependencies. Required to load-->
    <script src="node_modules/core-js/client/shim.min.js"></script>
    <script src="node_modules/zone.js/dist/zone.js"></script>
    <script src="node_modules/reflect-metadata/Reflect.js"></script>
   
    <!--Module loader-->
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    <script src="systemjs-config.js"></script>
    <script>
        System.import("app").catch(function(err) { console.log(err); });
     </script>
   </head>

<body>
    <div class="container">
        <h1 class="main-title">Welcome to Angular2!</h1>
            <!--Using AppComponent's selector. Angular2 is running-->
            <app-component>Application is loading...</app-component>
    </div>
</body>

</html>

In order for our Angular2 app to be up and running, we need to add some dependencies, which are the core-js shim, the zone.js and Reflect.js. After that, we can provide our systemjs configuration, with the Angular2 and Rx.js scripts.

The app-component selector, is the template of app.component.ts component. We'll see more about that in a moment.

systemjs-config.js

(function (global) {

    // Where to look for packages
    var map = {
        "app": "src",
        "@angular": "node_modules/@angular",
        "rxjs": "node_modules/rxjs"
    };

    // What to do when no filename and/or no extension exists
    var packages = {
        "app": { main: "main.js", defaultExtension: "js" },
        "rxjs": { main: "Rx.js", defaultExtension: "js" }
    };

    // Angular2 package names, as they are in node_modules/@angular/ directory
    var ngPackageNames = [
        "common",
        "compiler",
        "core",
        "platform-browser",
        "platform-browser-dynamic"
    ];

    // Mapping angular2 packages
    function packageUmd(packageName) {
        packages["@angular/" + packageName] = { main: "/bundles/" + packageName + ".umd.js", defaultExtension: "js" };
    };

    // Set UMD packages (for this sample project, in order to be safe with other environments like Karma, we should use the index as well)
    ngPackageNames.forEach(packageUmd);
    var config = {
        map: map,
        packages: packages
    };

    System.config(config);
})(this);

In this file, we provide configuration to SystemJS, on how to resolve imports (remember, SystemJS is a module loader, we need to tell it where it can find all the required packages/dependencies).
Comments provide useful information, so we won't say much about this file. You need to remember only that map maps configurations so you can be able to locate packages. The packages configuration gives you fine-grain control on modules. The main property is the entry JavaScript file to look under module directory, while the defaultExtension defines the extension this module will have if it is not defined in any import.
We locate all angular2 packages under bundles folder, which is located in each package directory. Ultimately, we are interested in the <package_name>.umd[.min].js file, which is exactly what we are loading at the moment.

Lastly, before we go into the Angular2 code, we need to add the styles.css file in css directory. So add this file, with the following code:

.container {
    background-color: #555;
    padding: 15px;
}

.main-title {
    color: #ddd;
}

.greeting {
    display: inline-block;
    padding: 35px;
}

.loader {
    color: #fff;
    font-weight: 300;
    font-size: 16px;
}

 

Angular2 code

app.module.ts

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { AppComponent } from "./app.component";
import { HomeComponent } from "./app/home.component";

@NgModule({
    imports: [BrowserModule],
    declarations: [AppComponent, HomeComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }

First, we add the application module, as every Angular application has at least one module class. Modules are very handy and help a lot to organize an application into cohesive blocks of functionality. To create a module, you need to import the NgModule decorator from @angular/core. Then you create a class, named AppModule here, which is decorated by NgModule. In this decorator, we register all the components in declarations property. If we had any services, we'd register them in providers property. Angular2 dependency injection takes care of the rest, so you don't need to register you components/directives/services/pipes in components anymore, everything is going into you module.

In imports property we inject other modules whose exposed classes are needed by component templates declared in this very module. BrowserModule is loaded here, which is a module every browser application must import. It registers critical application service providers and includes common directives. All these become immediately available and usable in any component this module contains.

Lastly, the bootstrap property identifies the application component or AppComponent as the bootstrap component, so Angular launches the application with this component serving as the root.

main.ts

In main.ts we do the application bootstraping. Main.ts (ultimately main.js) is the main entry point to our application, something we defined already in systemjs-config.js (main.js is mapped to "app" module).

We need the platformBrowserDynamic method, which is located under platform-browser-dynamic module, surprisingly, as many people would think that this is a core module. The thing is that bootstraping in Angular2 is platform specific, like bootstraping Angular2 from another environment like Apache Cordova, which requires a different kind of bootstrap function, as well as different library to be imported. Also, we import the AppModule component, which is something we've created.

After we execute the platformBrowserDynamic() method, it returns a PlatformRef, so we can call the bootstrapModule method that takes an NgModule as input and returns a Promise. If the module is loaded, success kicks-in, else error handler is called.

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';


platformBrowserDynamic().bootstrapModule(AppModule).then(
    success => console.log('AppComponent bootstrapped! Angular2 is running!'),
    error => console.log(error)
);

Take note that the app.module.ts is in the same directory as the main.ts. Be careful with the module paths, as this can sometimes be confusing. We have defined a module resolution strategy already in tsconfig.json. Look the imported module from the current directory (the file's directory), you don't need to use absolute paths or anything like that.

app.component.ts

In app.component.ts we need to create a Component. We are going to name it AppComponent. This component will have its template, as well style (app.component.html, app.component.css), as well as a child component (home.component).

Code:

import { Component, OnInit } from '@angular/core';
import { HomeComponent } from "./app/home.component";

@Component({
    moduleId: module.id,
    selector: 'app-component',
    templateUrl: './app.component.html',
    styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
    message: string;

    constructor() { }

    ngOnInit() {
        this.message = "Hello from AppComponent!";
    }
}

As you can see, a component has a very simple structure.
First, we have the imports, which are modules imported in our component.
Next we have the metadata, which is the @Component decorator declaration. This essentially describes the component.
Finally, we have the component definition, the class itself, in this case the AppComponent class, which goes with its implementation, of course.

We import Component and OnInit interface from @angular/core module.
Component is a decorator, while OnInit is an interface, it implements the ngOnInit method, which kicks-off when the component is initialized (it runs after the constructor of course).

Next we define all the metadata for the component. Let's take them one-by-one.

  • moduleId. We set it to module.id, which is the fully resolved filename, defined at module load time. Defining it, we can reference *.css, *.html files in component, for templateUrl and styleUrls, in a relative manner. Now we don't see this in app.component.ts, but I will show you what happens in home.component.ts later. Just be sure you have commonjs set as module in tsconfig.json. There is different approach on systemjs module or webpack, which we will discuss in another post.
  • selector. The name of the selector of the component. Remember the index.html with the <app-component> element? This is the AppComponent selector, so essentially, the template of the AppComponent will render.
  • templateUrl. We provide the path for the .html template file. It is just a string.
  • styleUrls: We provide in an array, all the paths for the .css files.

We name the class AppComponent and we make sure we export it as a module, so other files can access it (like the main.ts which imports AppComponent).

In class body, we just set the value of the message property.
Let's go the app.component.html to see how we render the message.

app.component.html

<div class="greeting-outer">
    <h2></h2>
    <home-component></home-component>
</div>

Nothing new here, just normal string interpolation, we put the message (the property we wish to render) into double braces {{}}.
Below, we have the <home-component> directive. Notice its usage. We didn't define anything in AppComponent, yet we can use the HomeComponent markup. The metadata become available from the application module, in which we registered the HomeComponent component. If we hadn't registered it there (in declarations property) the code above would throw an error, indicating it cannot find the <home-component> directive.

app.component.css

Standard CSS code for this file, no need to get into this, just paste the following code:

.greeting-outer {
    color: #666;
    background-color: #bbb;
    font-weight: 300;
    display: block;
    padding: 35px;
}

home.component.ts

For the home.component.ts we work in the same fashion with the app.component.ts, by getting the Component and OnInit interface. Next, we define the metadata and lastly, we define the class and its body. Let's see it.

import { Component, OnInit } from "@angular/core";

@Component({
    moduleId: module.id,
    selector: "home-component",
    templateUrl: "./home.component.html",
    styleUrls: ["./home.component.css"]
})
export class HomeComponent implements OnInit {
    message: string;

    ngOnInit() {
        this.message = "... and this is the HomeComponent, hello from here too!";
    }
}

Nothing new here, we just set a message on the message property, which will be rendered in home.component.html.

That's the power of components in Angular2. We can have infinite components in our UI, which can be children of the parent component, from them build a structure, with each one being responsible for individual operations, promoting component reuse.

Take a look at templateUrl and styleUrls properties. If we haven't defined the moduleId to be module.id we would get a 404 Not Found error for the .html and .css files. So we should define a path from the root of our application, which is the app, essentially where the main.ts resides.
Thanks to that though we are defining the resources in a relative manner.

home.component.html

Nothing special with the HomeComponent template.

<div class="greeting-inner">
    <h3></h3>
</div>

home.component.css

Finishing with the styling for the HomeComponent template.

.greeting-inner {
    background-color: #ccc;
    display: inline-block;
    padding: 35px;
    color: initial;
}

 

Application is ready

Everything is in place, so if you have followed along, you are now ready to run the application in the browser. Open a CMD (Ctrl + Shift + c) and type the following:

npm start

This will kick-off the lite web-server and, of course, the application itself.
Essentially, you are going to get this as a result.

Screenshot_1

Some tips

For developing on VSCode, be sure to download Angular2 TypeScript Snippets, by John Pappa. This can boost your productivity, when you are familiar with the bits and bolts of Angular2. Some of the snippets available in this extension:

TypeScript Snippets

ng2-component-root  // Angular 2 root App component
ng2-bootstrap       // Angular 2 bootstraping, for main.ts
ng2-component       // Angular 2 component
ng2-pipe            // Angular 2 pipe
ng2-route-config    // Angular 2 @RouteConfig
ng2-route-path      // Angular 2 routing path
ng2-service         // Angular 2 service
ng2-subscribe       // Angular 2 observable subscription

HTML Snippets

ng2-ngClass
ng2-ngFor
ng2-ngIf
ng2-ngModel
ng2-routerLink
ng2-ngStyle
ng2-ngSwitch

Visual studio 2015

If you intend to use VS 2015 to create an Angular2 application, just think about it twice. I had many problems such as looking for updates to resolve issues, like one with file indexing, which made VS 2015 crash if the node_modules folder was large enough.
For front-end code I would suggest go with VSCode, it just isn't that frustrating when developing, you don't want to be frustrated, do you?

Another reason is the lack of the hot module replacement, I want to write code for my front-end and immidiatelly see the changes in browser, I do not want to rebuild the application (yes it happened to me and I spend 3-4 hours trying to find what was wrong with my configuration) or refresh the browser. For gods sake, we are in 2016, with lots of tools in our hands that do exactly this job, why to be primitive because of the VS 2015 tooling issues?

Ah, and if you intend to use Angular-CLI with VS 2015 be prepared for the pain I mentioned above (VS 2015 super slow, crashes, etc.). The newest update partially resolved these issues, but it is not as fast as VSCode is.

Code

Download and play around with the code, which you can find on my Github page.

Share your thoughts below and take care.

This post is licensed under CC BY 4.0 by the author.

-

AngularJS with Typescript and SystemJS

Comments powered by Disqus.