Angular 2 Component Input Output

Use property binding and the @Input decorator to pass data into a component, and @Output and EventEmitter to pass data out and bind to an event.

Last updated Dec 2016, Angular version 2.3.x

The Application

This is the application we are building. It allows the color of the box to be changed by setting the red, green and blue values in the input fields. It's a working application so go ahead and give it a try.

The Components

The application consists of three types of component; ColorValueComponent allows the user to enter the color value in an input field, ColorBoxComponent displays the colored box (along with the red, green and blue values), and AppComponent acts as a container for the other components.

input output components

Let's dive in and see how these components communicate with each other.

One-time String Initialization with @Input

We use one-time string initialization to pass a string constant into a child component, but only once during start up. Here we pass initial values to the label and init-value properties of the custom element.

<color-value
    label="Blue"
    init-value="140"
    (value)="color.blue=$event">
</color-value>

This syntax only allows a string constant to be passed in and no change detection is performed.

To receive this value, the child component includes an @Input decorator on a property, as shown in the example below. Here, the label property is bound by matching the variable name, and the initialValue property is bound by matching the init-value alias in the @Input decorator.

export class ColorValueComponent implements OnInit {
    @Input() label: string;
    @Input("init-value") initialValue: string = "0";
    ...

The Application Code

Now back to our application. We use one-time string initialization in the parent component to set the label property on the <color-value> element. This property matches the label variable in the child component which has been decorated with @Input.

We do the same for init-value but this time we match the alias specified in the @Input decorator.

app.component.ts
import { Component } from '@angular/core';

import { RedGreenBlue } from "./red-green-blue";

@Component({
    selector: 'app',
    template: `
        <color-value label="Red"   init-value="10"  (value)="color.red=$event"></color-value>
        <color-value label="Green" init-value="200" (value)="color.green=$event"></color-value>
        <color-value label="Blue"  init-value="140" (value)="color.blue=$event"></color-value>
        <color-box [rgb]="color"></color-box>`,
})
export class AppComponent {
    private color: RedGreenBlue = new RedGreenBlue();
}
color-value.component.ts
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';

@Component({
    selector: 'color-value',
    template: `
        <p>
            {{label}}: 
            <input #color 
                   type="number" min="0" max="255" step="10" 
                   value="{{initialValue}}" 
                   (input)="sendColor(color.value)"/>
        </p>`,
})
export class ColorValueComponent implements OnInit {
    @Input() label: string;
    @Input("init-value") initialValue: string = "0";

    @Output("value") colorValueEvent: EventEmitter<string> = new EventEmitter();

    ngOnInit() {
        this.sendColor(this.initialValue);
    }

    private sendColor(color: string): void {
        this.colorValueEvent.emit(color);
    }
}

Property Binding with @Input

Next we pass the red, green and blue color values to the <color-box> element like this:


<color-box [rgb]="color"></color-box>

This time however, we are using property binding and not one-time initialization. The square brackets bind the value in quotes to the rgb property of the <color-box> element. The value in quotes is no longer a string constant but a template expression which reads the color variable from the component class.

export class AppComponent {
    private color: RedGreenBlue = new RedGreenBlue();
}

When the color object changes, the rgb property is automatically updated by the property binding.

The Application Code

In our application, the color object on AppComponent is used in the template expression of the rgb property binding; whenever the color object changes, the rgb property is automatically updated too.

ColorBoxComponent uses the @Input decorator to identify the property to bind to. In this case the property name in square brackets is matched to the rgb alias in the @Input decorator.

app.component.ts
import { Component } from '@angular/core';

import { RedGreenBlue } from "./red-green-blue";

@Component({
    selector: 'app',
    template: `
        <color-value label="Red"   init-value="10"  (value)="color.red=$event"></color-value>
        <color-value label="Green" init-value="200" (value)="color.green=$event"></color-value>
        <color-value label="Blue"  init-value="140" (value)="color.blue=$event"></color-value>
        <color-box [rgb]="color"></color-box>`,
})
export class AppComponent {
    private color: RedGreenBlue = new RedGreenBlue();
}
color-box.component.ts
import { Component, Input } from '@angular/core';

import { RedGreenBlue } from "./red-green-blue";

@Component({
    selector: 'color-box',
    template: `<pre [style.background-color]="redGreenBlue.style">{{redGreenBlue | json}}</pre>`,
    styles: ['pre {height: 90px; width: 140px; padding: 10px;}']
})
export class ColorBoxComponent {
    @Input("rgb") redGreenBlue: RedGreenBlue;
}

Event Binding with @Output

We can also pass values out of a child component back to the parent using an event binding. Let's see how.

In the child component we include an @Output decorator on a variable of type EventEmitter. This object will be used to fire our custom events.

@Output("value") colorValueEvent: EventEmitter<string> = new EventEmitter();

The value alias in the @Output decorator is the name of the event. If we omit the alias then the variable name is used instead (i.e. colorValueEvent). The <string> type in angle brackets is the data type of the payload to be sent with the event.

We trigger the event by calling the emit method on the EventEmitter object. This method takes one argument which is the payload of the event.

private sendColor(color: string): void {
    this.colorValueEvent.emit(color);
}

Back in the parent component we bind to this custom event by matching the name in parenthesis with the alias in the @Output decorator The payload is accessed using the built-in $event variable.

<color-value
    label="Blue"
    init-value="140"
    (value)="color.blue=$event">
</color-value>

The Application Code

Let's see how we use custom event binding in our application.

AppComponent binds to the value event on the <color-value> element. This matches the alias in the @Output decorator in ColorValueComponent.

The colorValueEvent object is of type EventEmitter and, when the emit method is executed on this object, the event is triggered and the argument sent as the payload. The parent component accesses the payload using the built-in $event variable.

app.component.ts
import { Component } from '@angular/core';

import { RedGreenBlue } from "./red-green-blue";

@Component({
    selector: 'app',
    template: `
        <color-value label="Red"   init-value="10"  (value)="color.red=$event"></color-value>
        <color-value label="Green" init-value="200" (value)="color.green=$event"></color-value>
        <color-value label="Blue"  init-value="140" (value)="color.blue=$event"></color-value>
        <color-box [rgb]="color"></color-box>`,
})
export class AppComponent {
    private color: RedGreenBlue = new RedGreenBlue();
}
color-value.component.ts
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';

@Component({
    selector: 'color-value',
    template: `
        <p>
            {{label}}: 
            <input #color 
                   type="number" min="0" max="255" step="10" 
                   value="{{initialValue}}" 
                   (input)="sendColor(color.value)"/>
        </p>`,
})
export class ColorValueComponent implements OnInit {
    @Input() label: string;
    @Input("init-value") initialValue: string = "0";

    @Output("value") colorValueEvent: EventEmitter<string> = new EventEmitter();

    ngOnInit() {
        this.sendColor(this.initialValue);
    }

    private sendColor(color: string): void {
        this.colorValueEvent.emit(color);
    }
}

Application Walk-through

Now let's step through the application to see how all the pieces fit together.

Setting Values with One-time Initialization

AppComponent is the root component and co-ordinates the flow of data between the <color-value> and the <color-box> custom elements.

From here, static string values are passed to the label and init-value properties of <color-value> using one-time string initialization. These values are then used in the template of ColorValueComponent which implements the <color-value> element.

app.component.ts
import { Component } from '@angular/core';

import { RedGreenBlue } from "./red-green-blue";

@Component({
    selector: 'app',
    template: `
        <color-value label="Red"   init-value="10"  (value)="color.red=$event"></color-value>
        <color-value label="Green" init-value="200" (value)="color.green=$event"></color-value>
        <color-value label="Blue"  init-value="140" (value)="color.blue=$event"></color-value>
        <color-box [rgb]="color"></color-box>`,
})
export class AppComponent {
    private color: RedGreenBlue = new RedGreenBlue();
}
color-value.component.ts
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';

@Component({
    selector: 'color-value',
    template: `
        <p>
            {{label}}: 
            <input #color 
                   type="number" min="0" max="255" step="10" 
                   value="{{initialValue}}" 
                   (input)="sendColor(color.value)"/>
        </p>`,
})
export class ColorValueComponent implements OnInit {
    @Input() label: string;
    @Input("init-value") initialValue: string = "0";

    @Output("value") colorValueEvent: EventEmitter<string> = new EventEmitter();

    ngOnInit() {
        this.sendColor(this.initialValue);
    }

    private sendColor(color: string): void {
        this.colorValueEvent.emit(color);
    }
}

Passing Data Out of a Component with Event Binding

Let's take a closer look at ColorValueComponent which captures the value entered in a text field and sends it back to the parent component.

First we define the colorValueEvent property to be of type EventEmitter with a generic argument of string which identifies the type of the event payload. The value alias in the @Output decorator is the name of the event.

So when the user changes a color value in the input field, the sendColor method is called on our class, and the emit method on colorValueEvent fires the event with the color value as the payload.

In the parent component, we bind to this event and use the built-in $event variable to access the payload and update the color object in the template expression.

color-value.component.ts
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';

@Component({
    selector: 'color-value',
    template: `
        <p>
            {{label}}: 
            <input #color 
                   type="number" min="0" max="255" step="10" 
                   value="{{initialValue}}" 
                   (input)="sendColor(color.value)"/>
        </p>`,
})
export class ColorValueComponent implements OnInit {
    @Input() label: string;
    @Input("init-value") initialValue: string = "0";

    @Output("value") colorValueEvent: EventEmitter<string> = new EventEmitter();

    ngOnInit() {
        this.sendColor(this.initialValue);
    }

    private sendColor(color: string): void {
        this.colorValueEvent.emit(color);
    }
}

Passing Data In to a Component with Property Binding

We use a property binding on the <color-box> element to pass the red, green and blue values to ColorBoxComponent which implements the <color-box> element. The rgb property in square brackets in the parent component is matched to the @Input decorator alias of the redGreenBlue variable in the child component.

So now, whenever the color object is updated by the event binding on the <color-value> element, the redGreenBlue object in ColorBoxComponent is automatically updated by the property binding.

app.component.ts
import { Component } from '@angular/core';

import { RedGreenBlue } from "./red-green-blue";

@Component({
    selector: 'app',
    template: `
        <color-value label="Red"   init-value="10"  (value)="color.red=$event"></color-value>
        <color-value label="Green" init-value="200" (value)="color.green=$event"></color-value>
        <color-value label="Blue"  init-value="140" (value)="color.blue=$event"></color-value>
        <color-box [rgb]="color"></color-box>`,
})
export class AppComponent {
    private color: RedGreenBlue = new RedGreenBlue();
}
color-box.component.ts
import { Component, Input } from '@angular/core';

import { RedGreenBlue } from "./red-green-blue";

@Component({
    selector: 'color-box',
    template: `<pre [style.background-color]="redGreenBlue.style">{{redGreenBlue | json}}</pre>`,
    styles: ['pre {height: 90px; width: 140px; padding: 10px;}']
})
export class ColorBoxComponent {
    @Input("rgb") redGreenBlue: RedGreenBlue;
}

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.
  • The Angular with TypeScript Tutorial - includes examples of components, template syntax, property binding, event binding, bootstrapping and more.
  • 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.
  • 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.