In this post I will explain the purpose of the new @Input and @Output annotations in Angular.

@Input

The purpose of @Input is to configure data bound input properties with support for change tracking. Basically it is the Angular way of injecting values directly into a component via property bindings in the DOM.

In my example I have defined a simple component with three @Input properties.

import {Component,Input, Output, EventEmitter, Attribute} from '@angular/core'; @Component({ template:` <div>Counter: {{counter}}</div> <div>Running total of counter values: {{sum}}</div> <div>Growing string: {{growingString}}</div>`, selector:'input-output' }) export class InputOutput{ private _growingString; @Output() stringChanged = new EventEmitter(); @Input() counter:number; @Input() fixedValue:string; @Input('mySum') sum:number; @Input() set growingString(value){ this._growingString = value.toLowerCase(); this.stringChanged.next({value:'changed to ' + this._growingString}); } get growingString(){ return this._growingString; } constructor(@Attribute('plain') plain){ console.log(plain); } }

Next I have created a new component where I instantiate the sample component in order to demonstrate how to pass data via the @Input properties.

import {Component,Input} from '@angular/core'; import {InputOutput} from './input-output'; @Component({ directives:[InputOutput], template:`<button (click)="update()">Update</button> <input-output plain="just a simple attribute" fixedValue="another hard coded value" (stringChanged)="myStringChanged($event)" [mySum]="runningTotal" [growingString]="myString" [counter]="count" </input-output>` }) export class InputOutputDemo{ count = 0; runningTotal = 0; myString = ''; myTitle = 'Input/Output Demo'; update(){ this.count++; this.runningTotal += this.count; this.myString += 'A'; } myStringChanged(val){ console.log(val); } }

Let's address the three different @Input properties one by one.

The most basic one is @Input counter since the name of the property matches the property binding in the DOM - [counter]=”count”. As I mentioned earlier @Input bindings are subject to change detection, so every time “count” changes, the counter value is updated with the new value.

In the next one - @Input('mySum') - I have defined an alias which let's me override the property name to be the alias instead of the original property name: [mySum]=”runningTotal”. Other than that everything is like before though.

It gets more interesting when we look at “growingString” since it allows for processing of the raw bound value via the setter function. This is added flexibility since we can use the setter to transform the value rather than using it directly. Nothing is changed when it comes to referencing the property in the DOM though.

In all cases so far we have been looking at bound property values using the new [] property syntax. Properties are ideal in cases where we want change tracking on our values, but what if we just want to hard code a value and assign it to our component? It turns out we can do this using regular DOM attributes. The attribute 'plain' is an example of this. Notice how I access the DOM attribute in the constructor by wrapping it in @Attribute('plain').

It turns out we actually have a second option for getting simple hard coded attributes from the markup. In my sample I have declared 'fixedValue' as an @Input. If I assign 'fixedValue' a value in the markup, without using [], it will still capture the value from the markup and assign it to the class property 'fixedValue'. In some cases this might be more convenient than @Attribute for fixed values where you don't need change tracking.

@Output

The purpose of @Output is to trigger custom events in components and create a channel for inter component communication. In my example I have defined stringChanged as an @Output, and every time the bound string changes, I emit a custom event. Notice how I am subscribing to the event in the markup using the (stringChanged)="myStringChanged($event)" syntax. Passing $event is important since it gives access to any data passed via the custom event.

As always my code is available on Github and as a live demo