Annotations
Understand how Angular decorators attach metadata to classes and class members so Angular can recognize components, directives, pipes, services, inputs, outputs, and modules.
Lesson content
What are Annotations in Angular? Annotations provide metadata that describes how Angular should process a class or class member. In Angular and TypeScript code, this metadata is commonly added using decorators beginning with the @ symbol. Simple Definition Decorator = @ Symbol + Metadata + Class or Class Member Example @Component({ selector: 'app-user', template: ` <h2> User Component </h2> ` }) export class UserComponent {} The @Component decorator tells Angular that UserComponent is a component. Annotation vs Decorator Annotation Decorator Metadata describing a class TypeScript syntax used to attach metadata Conceptual information Written using the @ symbol Example: component configuration Example: @Component() Easy Formula Annotation = Metadata Concept Decorator = Syntax that Applies Metadata Common Angular Decorators Decorator Purpose @Component Defines an Angular component @Directive Defines a custom directive @Pipe Defines a custom pipe @Injectable Makes a class available to dependency injection @NgModule Defines an NgModule in module-based applications @Input Receives data from a parent component @Output Sends custom events to a parent component @HostListener Listens to host or global DOM events @HostBinding Binds a class property to a host property @ViewChild Queries an element or child from the component view @ContentChild Queries projected content @Inject Specifies a dependency-injection token 1. @Component The @Component decorator marks a class as an Angular component. import { Component } from '@angular/core'; @Component({ selector: 'app-profile', templateUrl: './profile.component.html', styleUrl: './profile.component.css' }) export class ProfileComponent {} Common Component Metadata Property Purpose selector Defines the component's HTML element name template Defines an inline template templateUrl Loads a template from a file styles Defines inline styles styleUrl Loads styles from one file styleUrls Loads styles from multiple files imports Imports dependencies used by a standalone component providers Creates providers scoped to the component changeDetection Configures change-detection behavior 2. @Directive The @Directive decorator marks a class as an Angular directive. import { Directive, ElementRef, inject } from '@angular/core'; @Directive({ selector: '[appHighlight]' }) export class HighlightDirective { private element = inject( ElementRef ); constructor() { this.element .nativeElement .style .backgroundColor = 'yellow'; } } Usage <p appHighlight> Important message </p> Component vs Directive Component Directive Has its own template Usually adds behavior to an existing element Defines a user-interface section Changes element behavior or appearance Uses @Component Uses @Directive 3. @Pipe The @Pipe decorator marks a class as an Angular pipe. import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'initials' }) export class InitialsPipe implements PipeTransform { transform( value: string ): string { return value .split(' ') .map(word => word.charAt(0) ) .join('') .toUpperCase(); } } Usage <p> {{ 'Ajay Singh' | initials }} </p> Output AS 4. @Injectable The @Injectable decorator configures a class for Angular dependency injection. import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class UserService { getUsers() { return [ 'Ajay', 'Sneha' ]; } } providedIn: 'root' @Injectable({ providedIn: 'root' }) This makes one application-level service instance available through the root injector. Injecting the Service import { Component, inject } from '@angular/core'; @Component({ selector: 'app-users', template: `...` }) export class UsersComponent { private userService = inject( UserService ); } 5. @Input The @Input decorator marks a property that receives data from a parent component. Child Component import { Component, Input } from '@angular/core'; @Component({ selector: 'app-user-card', template: ` <h2> {{ name }} </h2> ` }) export class UserCardComponent { @Input() name = ''; } Parent Template <app-user-card [name]="userName" /> Modern Alternative import { input } from '@angular/core'; name = input(''); 6. @Output The @Output decorator marks a property as a custom component event. Child Component import { Component, EventEmitter, Output } from '@angular/core'; @Component({ selector: 'app-save-button', template: ` <button (click)="save()" > Save </button> ` }) export class SaveButtonComponent { @Output() saved = new EventEmitter<void>(); save() { this.saved.emit(); } } Parent Template <app-save-button (saved)="handleSave()" /> Modern Alternative import { output } from '@angular/core'; saved = output<void>(); 7. @HostListener The @HostListener decorator listens for events on the directive host element or another event target. import { Directive, HostListener } from '@angular/core'; @Directive({ selector: '[appClickLogger]' }) export class ClickLoggerDirective { @HostListener('click') handleClick() { console.log( 'Element clicked' ); } } Keyboard Event @HostListener( 'window:keydown', ['$event'] ) handleKeydown( event: KeyboardEvent ) { console.log( event.key ); } 8. @HostBinding The @HostBinding decorator binds a class property to a property, class, style, or attribute on the host element. import { Directive, HostBinding, HostListener } from '@angular/core'; @Directive({ selector: '[appActive]' }) export class ActiveDirective { @HostBinding( 'class.active' ) isActive = false; @HostListener('click') toggle() { this.isActive = !this.isActive; } } Result <button class="active"> Toggle </button> 9. @ViewChild The @ViewChild decorator retrieves an element, directive, or child component from the component's own view. import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core'; @Component({ selector: 'app-search', template: ` <input #searchInput /> ` }) export class SearchComponent implements AfterViewInit { @ViewChild( 'searchInput' ) searchInput!: ElementRef<HTMLInputElement>; ngAfterViewInit() { this.searchInput .nativeElement .focus(); } } 10. @ViewChildren The @ViewChildren decorator retrieves multiple matching items from the component view. @ViewChildren( UserCardComponent ) userCards!: QueryList< UserCardComponent >; 11. @ContentChild The @ContentChild decorator queries content projected into a component through ng-content . Container Component @Component({ selector: 'app-panel', template: ` <section> <ng-content /> </section> ` }) export class PanelComponent { @ContentChild( PanelTitleDirective ) title?: PanelTitleDirective; } 12. @ContentChildren The @ContentChildren decorator retrieves multiple matching items from projected content. @ContentChildren( MenuItemComponent ) menuItems!: QueryList< MenuItemComponent >; View Queries vs Content Queries View Query Content Query Reads the component's own template Reads projected content @ViewChild @ContentChild @ViewChildren @ContentChildren Commonly accessed after view initialization Commonly accessed after content initialization 13. @Inject The @Inject decorator explicitly identifies the dependency-injection token for a constructor parameter. import { Inject, InjectionToken, Injectable } from '@angular/core'; export const API_URL = new InjectionToken<string>( 'API_URL' ); @Injectable() export class ApiService { constructor( @Inject(API_URL) private apiUrl: string ) {} } Provider { provide: API_URL, useValue: 'https://api.example.com' } Modern Alternative private apiUrl = inject(API_URL); 14. @Optional The @Optional decorator allows a dependency to be missing. constructor( @Optional() private logger: LoggerService | null ) {} When no provider exists, Angular supplies null instead of throwing a missing-provider error. 15. @Self The @Self decorator tells Angular to search only the current injector. constructor( @Self() private control: NgControl ) {} 16. @SkipSelf The @SkipSelf decorator tells Angular to begin searching from the parent injector. constructor( @SkipSelf() private parentService: ConfigService ) {} 17. @Host The @Host decorator limits dependency lookup at the host boundary. constructor( @Host() private form: FormGroupDirective ) {} Dependency Resolution Decorators Decorator Search Behavior @Optional Returns null when no dependency is found @Self Searches only the current injector @SkipSelf Starts searching at the parent injector @Host Stops searching at the host boundary 18. @NgModule The @NgModule decorator marks a class as an Angular module. import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ declarations: [ LegacyUserComponent ], imports: [ CommonModule ], exports: [ LegacyUserComponent ] }) export class UserModule {} Common NgModule Metadata Property Purpose declarations Declares non-standalone components, directives, and pipes imports Imports dependencies required by the module exports Makes declarations available to other modules providers Registers dependency-injection providers bootstrap Identifies the root component in module-based applications Modern Angular recommends standalone components for new code. The @NgModule decorator remains important for understanding and maintaining module-based applications. Class Decorators Class decorators are placed directly above a class. @Component({...}) export class UserComponent {} @Directive({...}) export class HighlightDirective {} @Pipe({...}) export class InitialsPipe {} @Injectable({...}) export class UserService {} @NgModule({...}) export class UserModule {} Property Decorators Property decorators are applied to class properties. @Input() name = ''; @Output() saved = new EventEmitter(); @ViewChild('input') input!: ElementRef; @HostBinding( 'class.active' ) active = false; Method Decorators A method decorator is applied to a class method. @HostListener('click') handleClick() { console.log( 'Clicked' ); } Parameter Decorators Parameter decorators are applied to constructor parameters. constructor( @Inject(API_URL) apiUrl: string ) {} constructor( @Optional() logger: LoggerService | null ) {} Decorator Types Type Angular Examples Class decorator @Component , @Directive , @Pipe , @Injectable Property decorator @Input , @Output , @ViewChild Method decorator @HostListener Parameter decorator @Inject , @Optional , @Self Decorator Factory Most Angular decorators are decorator factories because they receive configuration and return a decorator. @Component({ selector: 'app-user', template: '<p>User</p>' }) Conceptual Structure DecoratorFactory( Configuration ) → Decorator How Angular Uses Decorator Metadata TypeScript Class + Angular Decorator ↓ Angular Reads Metadata ↓ Compiler Processes Class ↓ Component, Service, Directive, or Pipe Created Modern Initializer APIs Modern Angular also provides initializer APIs that replace some decorator-based member declarations. Decorator API Initializer API @Input() input() @Output() output() @ViewChild() viewChild() @ViewChildren() viewChildren() @ContentChild() contentChild() @ContentChildren() contentChildren() Modern Input Example name = input.required<string>(); Modern Output Example selected = output<number>(); Modern View Query Example searchInput = viewChild< ElementRef<HTMLInputElement> >( 'searchInput' ); Custom TypeScript Decorator TypeScript also supports custom decorators outside Angular-specific APIs. function LogClass( constructor: Function ) { console.log( 'Class created:', constructor.name ); } @LogClass class UserRepository {} Angular developers normally use Angular's provided decorators for framework metadata. Common Mistakes 1. Forgetting the Decorator Import import { Component } from '@angular/core'; 2. Forgetting Parentheses Wrong: @Component export class AppComponent {} Correct: @Component({ selector: 'app-root', template: '<p>App</p>' }) export class AppComponent {} 3. Using @Component Without Metadata A component requires configuration such as a selector and template. 4. Using @Input Without Parent Binding An input receives its value only when the parent provides one or when a default value exists. 5. Mutating an Input Treat parent-provided input data as read-only and emit an event when requesting a change. 6. Forgetting EventEmitter for Traditional Outputs @Output() saved = new EventEmitter<void>(); 7. Using NgModule for Every New Feature Prefer standalone components and route-level providers for new Angular applications. 8. Confusing @Injectable with Service Creation The decorator configures dependency injection. The class still needs a provider such as providedIn: 'root' or an explicit provider registration. Best Practices Use the correct decorator for each Angular class Keep decorator metadata clear and focused Use strongly typed inputs and outputs Prefer initializer APIs such as input() and output() in new code Use @Injectable with an appropriate provider scope Use host bindings and listeners only for host-related behavior Prefer signal-based query APIs in new code Use standalone components for new applications Understand decorator APIs because they remain common in existing projects Interview Questions What is an annotation in Angular? An annotation is metadata that tells Angular how a class or class member should be processed. What is a decorator? A decorator is TypeScript syntax beginning with @ that attaches metadata or behavior to a class or class member. What does @Component do? It marks a class as an Angular component and supplies component configuration metadata. What does @Injectable do? It configures a class so Angular can create it through dependency injection. What is the difference between @Component and @Directive? A component has its own template, while a directive normally adds behavior to an existing element. What are property decorators? Property decorators are applied to class properties. Examples include @Input , @Output , and @ViewChild . What are parameter decorators? Parameter decorators configure constructor dependency resolution. Examples include @Inject , @Optional , and @Self . What is the modern alternative to @Input? input() What is the modern alternative to @Output? output() Is @NgModule required for every Angular application? No. Modern Angular applications can use standalone components and application providers without defining an application NgModule. Key Point Angular decorators attach metadata that allows Angular to recognize and configure framework classes and class members. Easy Formula @Component = UI Component @Directive = DOM Behavior @Pipe = Value Transformation @Injectable = Dependency Injection @Input = Parent → Child @Output = Child → Parent @ViewChild = View Query @ContentChild = Projected Content Query @NgModule = Module Configuration