Suggest an editImprove this articleRefine the answer for “@input and @output decorators in Angular”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`@Input`** passes data from a parent component down to a child. **`@Output`** with `EventEmitter` fires events from the child back up to the parent. ```typescript @Input() name = ''; // parent provides @Output() removed = new EventEmitter<string>(); // child notifies parent ``` ```html <app-card [name]="user.name" (removed)="remove($event)"></app-card> ``` **Key point:** binding is one-way in both cases. For two-way sync, pair them as `value` and `valueChange`.Shown above the full answer for quick recall.Answer (EN)Image**`@Input` and `@Output`** are Angular decorators that wire parent-child component communication: `@Input` passes data from parent to child, `@Output` emits events from child to parent. ## Theory ### TL;DR - `@Input` = parent hands data down; the child reads it but cannot push changes back to the parent's copy - `@Output` = child fires an event upward using `EventEmitter`; the parent decides what to do with it - Analogy: parent passes a note to a kid (`@Input`); the kid shouts "Done!" back (`@Output`) - Use both for reusable, presentational components; switch to a service when siblings share state or state is global ### Quick example ```typescript // child.component.ts import { Component, Input, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-child', template: `<button (click)="notify()">Finish</button>` }) export class ChildComponent { @Input() message = 'Hello'; // receives from parent @Output() done = new EventEmitter<string>(); // sends to parent notify() { this.done.emit('Task complete!'); } } ``` ```html <!-- parent.component.html --> <app-child [message]="parentMsg" (done)="onDone($event)"></app-child> ``` `[message]` is property binding - data flows in. `(done)` is event binding - the parent method runs when the child calls `.emit()`. ### Key difference `@Input` creates a one-way data binding: when the parent value changes, Angular updates the child during the next change detection cycle. `@Output` works in the opposite direction - the child holds an `EventEmitter` and calls `.emit()` to trigger a parent method. The child has no idea what the parent will do with that event, which keeps the two components decoupled. ### When to use - Pass user profile data to a display card component → `@Input` - A delete button in a list item needs to notify the parent → `@Output` - A reusable field that shows a value and reports changes → both - Two sibling components share state, or state is needed across multiple features → skip both, use a service with `BehaviorSubject` or NgRx ### How Angular handles it internally Angular's compiler processes `@Input` and `@Output` during template compilation, turning them into property bindings and event listeners. When an `@Input` value changes, Angular calls `ngOnChanges` on the child. `@Output` wraps `EventEmitter` in zone.js-patched events, so each `.emit()` schedules a change detection run rather than triggering it immediately. This avoids infinite loops when an output causes a parent state change. ### Common mistakes **Forgetting parentheses on the output binding:** ```html <!-- Wrong: Angular treats this as a property binding, not an event --> <app-child done="handle()"></app-child> <!-- Correct --> <app-child (done)="handle($event)"></app-child> ``` **Mutating the `@Input` array or object directly in the child:** ```typescript // Wrong: parent never knows the array changed @Input() items: string[] = []; ngOnInit() { this.items.push('new'); } // Correct: emit the updated collection back @Output() itemsChange = new EventEmitter<string[]>(); add(item: string) { this.itemsChange.emit([...this.items, item]); } ``` One-way binding means the parent's reference is not updated. Developers switching from React sometimes hit this - in React, props are immutable by convention, but Angular does not enforce it at the object level. **Using `@Output` without `EventEmitter`:** ```typescript // Wrong: TypeScript compiles this, but runtime throws @Output() done: string; // Correct @Output() done = new EventEmitter<string>(); ``` **Skipping `transform` for boolean attributes:** ```html <!-- Wrong: passes the string "true", not a boolean --> <app-button [disabled]="'true'"></app-button> ``` ```typescript // Correct: booleanAttribute converts the string to a real boolean @Input({ transform: booleanAttribute }) disabled = false; ``` ### Real-world usage - Angular Material: `mat-slider` uses `@Input() value` and `@Output() valueChange` for two-way binding - PrimeNG: `p-table` takes `@Input() options` and emits `@Output() onRowSelect` - NG Bootstrap: `ngb-datepicker` accepts a model via `@Input` and fires `@Output() navigate` on month change - Angular's built-in `required` option (since Angular 14.3+): `@Input({ required: true }) id!: string` throws `NG0303` in dev mode if the parent forgets to bind it ### Follow-up questions **Q:** What is the difference between `@Input` and property binding? **A:** `@Input` marks a class property as bindable from outside the component. Property binding `[prop]="value"` in the parent template is how you actually supply the value. One is the declaration, the other is the usage. **Q:** How does `ChangeDetectionStrategy.OnPush` interact with `@Input`? **A:** With OnPush, Angular only re-checks a component when its `@Input` references change (not deep mutations), or when an event fires. If you mutate an `@Input` array in place without creating a new reference, the component will not re-render. **Q:** What does `@Input({ required: true })` do? **A:** Available since Angular 14.3+. The compiler throws `NG0303` at build time if the parent does not bind that input. Useful for properties that make no sense without a value, like a row `id` in a data table. **Q:** Why use `EventEmitter` instead of a plain `Subject` for `@Output`? **A:** Angular template event binding is designed to work with `EventEmitter`. A `Subject` will function at runtime, but `EventEmitter` communicates intent clearly and keeps the API consistent with Angular conventions. **Q:** When does passing data through `@Input`/`@Output` become a problem, and what do you do instead? **A:** Once data has to pass through more than two levels of nesting, or two sibling components need the same state, it gets unwieldy fast. The standard move is a shared service with a `BehaviorSubject`. Add `ChangeDetectionStrategy.OnPush` across those components to cut unnecessary re-renders. For large-scale cross-feature state, NgRx or Angular Signals store are the right tools. ## Examples ### Basic: counter with two-way sync ```typescript // counter.component.ts @Component({ selector: 'app-counter', template: ` <p>Count: {{ count }}</p> <button (click)="increment()">+</button> ` }) export class CounterComponent { @Input() count = 0; @Output() countChange = new EventEmitter<number>(); increment() { this.countChange.emit(this.count + 1); // never mutates count directly } } ``` ```html <!-- parent.component.html --> <app-counter [count]="counter" (countChange)="counter = $event"></app-counter> ``` The child never modifies its own `count`. It emits the new value and the parent updates the source of truth. Name an input/output pair as `value` and `valueChange` and Angular's `[(value)]` two-way binding syntax works automatically. ### Intermediate: user list with multiple outputs ```typescript // user-item.component.ts @Component({ selector: 'app-user-item', template: ` <div> {{ user.name }} ({{ user.active ? 'Active' : 'Inactive' }}) <button (click)="toggle()">Toggle</button> <button (click)="remove()">Delete</button> </div> ` }) export class UserItemComponent { @Input() user!: { name: string; active: boolean }; @Output() userToggled = new EventEmitter<{ name: string; active: boolean }>(); @Output() userDeleted = new EventEmitter<string>(); toggle() { this.userToggled.emit({ ...this.user, active: !this.user.active }); } remove() { this.userDeleted.emit(this.user.name); } } ``` ```html <!-- parent.component.html --> <app-user-item *ngFor="let u of users" [user]="u" (userToggled)="updateUser($event)" (userDeleted)="deleteUser($event)" ></app-user-item> ``` One component, two outputs. The parent owns the `users` array and is responsible for updating it. The child only knows its own `user` object and which button was clicked. Business logic stays out of the display component. ### Advanced: required input with alias and transform ```typescript // data-row.component.ts @Component({ selector: 'app-data-row', template: `<p>ID: {{ id }} | Disabled: {{ disabled }}</p>` }) export class DataRowComponent { @Input({ required: true, alias: 'rowId' }) id!: string; @Input({ transform: booleanAttribute }) disabled = false; } ``` ```html <!-- Works fine --> <app-data-row [rowId]="'abc-123'" disabled></app-data-row> <!-- Throws NG0303 in dev: Missing required input 'rowId' --> <app-data-row></app-data-row> ``` `required: true` makes the compiler catch a missing binding before runtime. `alias` lets the template use `rowId` while the class property is named `id`. `booleanAttribute` handles the string-to-boolean conversion: the attribute `disabled` with no value becomes `true`, not `"true"`.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.