The Angular 2 with TypeScript Tutorial

Learn Angular 2 with TypeScript. This tutorial includes examples of components, template syntax, property binding, event binding, bootstrapping and more.

The Application

This is the block counter application we are building.

Custom Element

First, we add a custom element called <block-counter> to the index.html page.

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Angular Block Counter</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Polyfill for older browsers -->
    <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>
    <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>
</head>

<body>
    <block-counter>Loading...</block-counter>
</body>

</html>

To implement this custom element we need to create a component.

Component

Components define custom elements such as <todo-list>, <user-details> or, in our case, the <block-counter> element which we added to our index.html page.

The component class is written in TypeScript and defines the data and application logic for the component. The @Component decorator provides additional meta-data for the class.

block-counter.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'block-counter',
    template:  `
        <button (click)="updateCount(-1)" [disabled]="!count"> - </button>
        <button (click)="updateCount()"> + </button>
        <span [innerHTML]="blocks" class="blocks"></span>
        {{count || 'none'}}`,
    styles: ['.blocks {color: PaleGreen;']
})
export class BlockCounterComponent {

    private count: number = 4;

    private updateCount(adjustment:number = 1) {
        this.count += adjustment;
    }

    private get blocks() {
        return '&#9609;'.repeat(this.count);
    }
}

So when the application starts, Angular will locate the <block-counter> element using selector, insert the contents of the template between the tags, and apply the CSS rules specified in the styles property. These styles only apply to this component and won't "leak" to the outer HTML.

The template accesses properties and calls methods on the component class using property bindings, event bindings and interpolation. We'll take a look at this next.

Template Syntax

Interpolation

Angular evaluates template expressions in curly braces such as {{ 1 + 2 }}, {{'Hello' + user.name}} or {{count || 'none'}} using the component class as the execution context (which is why we can use count in our example). The result is then substituted into the template using interpolation.

Event Binding

An event binding executes the template statement in quotes whenever the DOM event in parentheses (such as mouseover, keyup or click) is detected. So, in this example, the updateCount method is called whenever a click event is received on either of the two buttons.

block-counter.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'block-counter',
    template:  `
        <button (click)="updateCount(-1)" [disabled]="!count"> - </button>
        <button (click)="updateCount()"> + </button>
        <span [innerHTML]="blocks" class="blocks"></span>
        {{count || 'none'}}`,
    styles: ['.blocks {color: PaleGreen;']
})
export class BlockCounterComponent {

    private count: number = 4;

    private updateCount(adjustment:number = 1) {
        this.count += adjustment;
    }

    private get blocks() {
        return '&#9609;'.repeat(this.count);
    }
}

Property Binding

A property binding binds the result of the template expression in quotes to the DOM property (such as hidden, innerHTML or disabled) in square brackets. Here, the disabled property is used to enable or disable the button based on the result of the template expression.

Also, the innerHTML property of this span element is set to the results of the blocks getter method. We use innerHTML rather than interpolation here to insert the value as HTML. Interpolation escapes HTML and would display &#9609;&#9609;&#9609; rather than ▉▉▉.

Bootstrapping

We start the application by calling the Angular bootstrapModule function on the root application module, which in our case is AppModule.

main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);
app.module.ts
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { BlockCounterComponent }   from './block-counter.component';

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

At this point, Angular reads the BlockCounterComponent meta-data from the @Component decorator, locates an element tag named <block-counter> using the selector, loads the template between those tags, and applies the CSS styles.

block-counter.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'block-counter',
    template:  `
        <button (click)="updateCount(-1)" [disabled]="!count"> - </button>
        <button (click)="updateCount()"> + </button>
        <span [innerHTML]="blocks" class="blocks"></span>
        {{count || 'none'}}`,
    styles: ['.blocks {color: PaleGreen;']
})
export class BlockCounterComponent {

    private count: number = 4;

    private updateCount(adjustment:number = 1) {
        this.count += adjustment;
    }

    private get blocks() {
        return '&#9609;'.repeat(this.count);
    }
}

Where Next?

To find out more about Angular and TypeScript, check out these tutorials.

  • Hello World - Implement a super-simple <hello-world> custom element using an Angular and TypeScript.
  • Configuration - Configure Angular and TypeScript to download dependencies from node modules or a CDN, and to compile the TypeScript during development or in the browser at runtime.
  • Templates - introduction to inline and external templates.
  • Interpolation - use curly braces and template expressions to output data on the page.
  • Property Binding - bind to DOM properties using square brackets and template expressions.
  • Event Binding - handle DOM events using parentheses and template statements.
  • Two-way Binding - combine property and event binding to create two-way binding with ngModel.
  • Input Binding - bind to <input> fields such as text, textarea, checkbox, radio and select.
  • Built-in Directives - see how to use built-in directives ngIf, ngSwitch, ngFor, ngClass and ngStyle.
  • Component Input Output - use @Input and @Output to pass data in to and out of a component.
  • Angular Router - Use the Angular router to navigate between components when the user clicks a link.
  • Nested Child Routes - An example of how child routes allow navigation between multiple views when a user clicks a link in a sub-menu.