How to cancel a component event from output properties in Angular
Sometimes a component needs to raise an event to the parent component to notify them of action e.g., click. In this post, we will examine how a parent component can cancel or prevent a default action from taking place.

In Angular, components expose output properties that use EventEmitters
to fire an event. However, sometimes we may want to cancel or prevent the emission based on logic provided by the parent component. Out-of-the-box Angular does not provide a mechanism for canceling events. How can we enable our parent component to cancel events emitted by a child component?
Let’s first dive into a concrete example. Suppose you’re building a tab control component that allows the user to display different content within tabs.

The tab component owns both the display of the projected content and navigation of the selected tab with an architecture similar to Angular Material Tabs.
<tab-group>
<tab label="my label">
<!-- tab content -->
</tab>
</tab-group>
See a working version of the component on StackBlitz.
Now the consumer of the component wants to prevent the tabs from navigating when the user has stale or unsaved data. How can we provide the consumer cancellation hooks to make this happen?
Using an Input Property
Let’s update the tab-group
component to take an input property to control the cancelation event. This property is named canActivateTab
, and will accept a function that returns a boolean value. Also, by default, if the consumer does not pass a value to the canActivateTab
Input, we will default to true. When a tab is selected, we will invoke the canActivateTab
function to see if the consumer wants to cancel the event.
@Component({
selector: 'tab-group',
templateUrl: './tab-group.component.html',
styleUrls: ['./tab-group.component.css']
})
export class TabGroupComponent {
// Additional tab group component code omitted
@Input()
canActivateTab = () => true;
_onSelectTab(tab: TabComponent) {
if(this.canActivate()) {
this._setTab(tab);
}
}
}
To use the canActivateTab
property, the consumer of our tab-group component provides a function as an input.
<tab-group [canActivateTab]="_onCanActivateTab">
<tab label="my label">
<!-- tab content -->
</tab>
</tab-group>
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
_onCanActivateTab() {
// insert conditional tab switching logic
return true;
}
}
At first glance, this looks like a great solution! Consumers can can easily create a function that returns a boolean value to control the behavior. However, you will quickly realize that within your _onCanActivateTab
function, you no longer have access to other properties of the class.
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
private cancelTab = true;
_onCanActivateTab() {
return this.cancelTab; // ❌ Returns undefined!
}
}
Since the tab-group
component invokes the provided function, the context of “this” is incorrect. (read more on this)
In order to ensure the context of “this” is set to our AppComponent
class we either need to invoke the bind
method passing the correct context of “this” (the component class).
<tab-group [canActivateTab]="_onCanActivateTab.bind(this)">
<tab label="my label">
<!-- tab content -->
</tab>
</tab-group>
Using bind
isn’t a deal-breaker by any means and is the solution to pass the proper context. However, I dislike that the consumer of my component needs to have an understanding of JavaScript’s “this” context. While an essential part of the JavaScript language, we’re trying to build easy to use components that just work within the Angular ecosystem. With that in mind, let’s try another solution.
Input Property StackBlitz Demo
Using an Output Property
Instead of relying on an input property, what about an output property?
Let’s modify the tab-group
component to output an event when the user attempts to change the tab content. First, create an interface that contains a cancel property.
export interface TabActivateArgs {
cancel: boolean;
}
Next, add a new Output that emits the TabActivateArgs
.
@Component({
selector: 'tab-group',
templateUrl: './tab-group.component.html',
styleUrls: ['./tab-group.component.css']
})
export class TabGroupComponent {
@Output()
canTabActivate = new EventEmitter<TabActivateArgs>();
_selectTab(tab: TabComponent) {
const activateArgs = {cancel: false};
this.canTabActivate.emit(activateArgs);
if(activateArgs.cancel) {
return;
}
this._setTab(tab);
}
}
When the user attempts to switch tabs, we will emit the canTabSwitch
output property. The consumer of the component binds to this event within the parent component and updates the cancel
property to true
to cancel the event.
<tab-group (canTabActivate)="_onCanTabActivate($event)">
<tab label="my label">
<!-- tab content -->
</tab>
</tab-group>
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
_onCanTabActivate(args: TabActivateArgs) {
// logic to determine if tab switching should be cancelled
args.cancel = true;
}
}
The output property works because, by default, EventEmitters
are synchronous.
Thinking about the solution a little more, I was concerned this pattern would fall apart when using the component as a Web Component (Angular Elements). Good news! While EventEmitters
are modified to dispatch a custom events, custom events dispatch synchronously!
If providing a mutable property to your consumer feels a bit awkward, consider providing a function cancel
within the event arguments.
_selectTab(tab: TabComponent) {
let cancelled = false;
const activateArgs = {
cancel: () => { cancelled = true; }
};
this.canTabActivate.emit(activateArgs);
if(cancelled) {
return;
}
this._setTab(tab);
}
}
The consumer invokes this function to cancel the event.
To me, this is a much cleaner solution to the problem. No fancy knowledge of JavaScript required, just the built-in conventions of Angular.
Output Property StackBlitz Demo
Conclusion
While Angular does not provide an out-of-the-box pattern for canceling events, utilizing Output properties to facilitate this behavior feels like a cleaner solution.
Have another solution? I’d love to hear about it! Fork my StackBlitz and show me what you’re thinking.