Output Events

You use @Output decorator in combination with the EventEmitter type to create component events.

To better understand how events are used and work let's introduce and see a component event in action.

Raising Events

We are going to extend our Header component with a "click" event. Every time the header title gets clicked the component is going to raise a "titleClick" event.

// src/app/components/header.component.ts

import { ..., Output, EventEmitter } from '@angular/core';

@Component({...})
export class HeaderComponent {
    // ...

    @Output()
    titleClick = new EventEmitter();
}

Now to raise the newly introduced event from the component, we call its next method:

this.titleClick.next();

Next, we need to wire component template with the underlying method handleTitleClick. The latter is going to be responsible for raising the corresponding titleClick event.

<!-- src/app/components/header.component.html -->

<div class="app-header">
  <div class="app-header-title" (click)="handleTitleClick()">{{ title }}</div>
</div>

The handleTitleClick implementation can be as follows:

// src/app/components/header.component.ts

@Component({...})
export class HeaderComponent {
    ...

    @Output()
    titleClick = new EventEmitter();

    handleTitleClick() {
        this.titleClick.next();
    }
}

Handling Events

We have extended our Header component to raise an event once a user clicks the title. Now let's make our main application handle this event and display click counter on the page.

<!-- src/app/app.component.html -->

<app-header
  [title]="title"
  (titleClick)="onTitleClicked()">
</app-header>

<div>
  Header clicks: {{ headerClicks }}
</div>

<app-footer></app-footer>

As you can see from the code above the main application component subscribes to the titleClick event and uses onTitleClicked method as an event handler.

The component also displays the headerClicks property value for us to see the event handler works. The final thing we need right now is incrementing the counter property like in the code below:

// src/app/app.component.ts

@Component({...})
export class AppComponent {

    headerClicks = 0;

    onTitleClicked() {
        this.headerClicks += 1;
    }

}

Now if you run the web application and click several times on the header text, you should see the clicks counter increase in real time.

Typed Events

The EventEmitter type we used for earlier is a generic type, and by default takes the type variable of any.

EventEmitter<any>

In many cases, you may want to provide the additional event arguments to enable better handling of your component events. For example, a "click" event may expose details on the mouse cursor position or a "textChanged" event that exposes old and new text values.

In the previous section, we have already created a Header component that raises generic "titleClick" event with no arguments. To compare both approaches let's now update Footer component with the similar event but of a specific type.

The Footer is going to count the number of clicks itself and provide the value as part of the event. The main application is no longer required to keep track on clicks as it is going to get exact values from the corresponding event arguments.

If you remember, we created a Footer component using the following Angular CLI command:

ng g component components/footer

First, create a FooterClickedEvent class to hold the clicks-related information for our titleClicked event:

// src/app/components/footer/footer-clicked.event.ts

export class FooterClickedEvent {

    constructor(public readonly totalClicks: number = 0) {
    }

}

For the sake of simplicity, we are going to create a class with a single read-only property totalClicks we assign in the constructor, and that defaults to zero if not provided.

Next, edit your footer component and update its code with the following pieces that add a title input property and titleClicked output event:

// src/app/components/footer/footer.component.ts

import { ..., Output, EventEmitter } from '@angular/core';
import { FooterClickedEvent } from './footer-clicked.event';

@Component({...})
export class FooterComponent {

    @Input()
    title = 'Footer';

    @Output()
    titleClick = new EventEmitter<FooterClickedEvent>();

}

As you can see above, we also declare a private property totalClicks to hold the overall clicks count.

Note how we use EventEmitter type this time. Using FooterClickedEvent as an EventEmitter's type variable allows us now to create an instance of the given type and emit as an event.

// src/app/components/footer/footer.component.ts

@Component({...})
export class FooterComponent {
    ...

    private totalClicks = 0;

    handleTitleClick() {
        const event = new FooterClickedEvent(++this.totalClicks)
        this.titleClick.next(event);
    }

}

Now we can update the component template to display the title and handle mouse clicks:

<!-- src/app/components/footer/footer.component.html -->

<p>
  <span (click)="handleTitleClick()">{{ title }}</span>
</p>

Every time user clicks the "title" element of the Footer, the component is going to increment clicks counter and raise an event with its actual value.

Accessing Event Parameters

Angular provides a way to access the original event by using a special $event variable that you can pass to your handlers.

<app-footer
  title="My footer"
  (titleClick)="onHeaderClicked($event)">
</app-footer>

In our current case, we handle the titleClick event and pass original FooterClickedEvent to the onHeaderClicked handler inside application controller. That provides access to the totalClicks property we created earlier.

DOM events

Please keep in mind that "$event" usage applies to all events, either custom or standard DOM ones. For instance, you can inspect "click", "hover", "input" and many other DOM events from within your class methods.

Let's now update our main application component to display the number of times the user clicked the Footer.

// src/app/app.component.ts
// ...
import { FooterClickedEvent } from './components/footer/footer-clicked.event';

@Component({...})
export class AppComponent {
    ...
    footerClicks = 0;

    onHeaderClicked(event: FooterClickedEvent) {
        this.footerClicks = event.totalClicks;
    }
}

As you can see in the example above, we now can import the FooterClickedEvent type and use with the event handler parameters to get type checking and code completion support in your IDE.

Finally, let's update the main component template to display click counters for the Footer alongside the Header.

<!-- src/app/app.component.html -->

<app-header
  [title]="title"
  (titleClick)="onTitleClicked()">
</app-header>

<div>Header clicks: {{ headerClicks }}</div>
<div>Footer clicks: {{ footerClicks }}</div>

<app-footer
  title="My footer"
  (titleClick)="onHeaderClicked($event)">
</app-footer>

You can now run your web application and make several clicks on Header and Footer components to see all event handlers in action. You should see results similar to the following:

Aliased Outputs

Similar to the @Input decorator the @Output one also supports custom aliases for event names and takes the name of the decorated property as the default value.

In the previous examples, we used the titleClick for the output property name:

// src/app/components/footer/footer.component.ts

@Component({...})
export class FooterComponent {
    // ...

    @Output()
    titleClick = new EventEmitter<FooterClickedEvent>();
}

You could also provide the title-click alias for the event like below:

// src/app/components/footer/footer.component.ts

@Component({...})
export class FooterComponent {
    // ...

    @Output('title-click')
    titleClick = new EventEmitter<FooterClickedEvent>();
}

In this case the "official" (or public) event name for the Footer's titleClick component would be title-click, and not titleClick:

<app-footer
  title="My footer"
  (title-click)="onHeaderClicked($event)">
</app-footer>

Avoid aliasing inputs and outputs

According to the Angular Style Guide (Style 05-13), you should avoid using alias for the @Input and @Output decorators except when is needed and serves an important purpose.

Two names for the same property is confusing and may require additional documentation and maintenance over time.