Angular

Data Binding

15 Questions

Angular supports four types of data binding that connect the component class to its template. Interpolation and property binding are one-way from component to view. Event binding is one-way from view to component. Two-way binding combines both directions using the banana-in-a-box syntax [(ngModel)].
<!-- 1. Interpolation (one-way: component to view) -->
<p>{{ title }}</p>

<!-- 2. Property binding (one-way: component to view) -->
<img [src]="imageUrl" />

<!-- 3. Event binding (one-way: view to component) -->
<button (click)="onClick()">Click</button>

<!-- 4. Two-way binding (both directions) -->
<input [(ngModel)]="name" />
Interpolation and property binding display data from the component. Event binding captures user actions and sends them to the component. Two-way binding keeps the view and model in sync automatically.

Why it matters: Tests understanding of Angular's data flow architecture. Shows you know when to use each binding type for different scenarios.

Real applications: Display data with interpolation ({{ title }}), bind image URLs with property binding ([src]), respond to clicks with event binding ((click)), and keep form inputs synchronized with two-way binding ([(ngModel)]).

Common mistakes: Developers confuse when to use [] vs {{}} vs (). They try to use two-way binding everywhere instead of understanding the different data flows. They don't realize each type serves specific purposes.

Interpolation uses double curly braces {{ }} to embed expressions directly in the template. Angular evaluates the expression and converts the result to a string for display. It is the simplest form of one-way data binding from the component to the view. You can use property access, method calls, and simple expressions inside the curly braces.
@Component({
  selector: 'app-greet',
  template: '<h1>Welcome, {{ fullName }}!</h1><p>2 + 2 = {{ 2 + 2 }}</p>'
})
export class GreetComponent {
  firstName = 'John';
  lastName = 'Doe';
  get fullName() { return this.firstName + ' ' + this.lastName; }
}
Interpolation supports simple expressions, method calls, and property access but does not support assignments, chaining with semicolons, or the new keyword. Expressions should be simple, fast, and free of side effects.

Why it matters: Tests knowledge of Angular's template syntax and expression evaluation. Shows understanding of what's allowed in templates.

Real applications: Display user names ({{ fullName }}), compute totals ({{ price * quantity }}), call getters ({{ isActive }}), show dates formatted ({{ date | date:'short' }}).

Common mistakes: Developers try assignments in interpolation ({{ x = 5 }}). They create complex expressions instead of using component methods. They don't realize expression evaluation runs frequently affecting performance.

Property binding sets a DOM element property or a directive/component input to a value from the component class. It uses square bracket [] syntax around the property name. Unlike interpolation, property binding can pass non-string values like booleans, objects, and arrays directly. It is a one-way binding from the component to the DOM.
<!-- Bind to element property -->
<img [src]="imageUrl" [alt]="imageAlt" />

<!-- Bind to component input -->
<app-child [user]="currentUser"></app-child>

<!-- Bind to disabled property -->
<button [disabled]="isSubmitting">Submit</button>
Property binding is one-way from the component to the DOM and updates whenever the expression value changes. Use it when you need to pass non-string data or bind to element properties like disabled, hidden, or src.

Why it matters: Tests knowledge of property vs attribute differences and when to use property binding. Shows understanding of the DOM model.

Real applications: Bind image sources dynamically, disable buttons based on form state, hide elements conditionally, pass complex objects to child components.

Common mistakes: Developers use interpolation instead of property binding for dynamic image URLs. They bind to wrong attributes like binding [value] when they meant the input's value property. They don't understand property vs attribute distinction.

Event binding listens for DOM events and calls a component method when the event fires. It uses parentheses () syntax around the event name. This is the one-way binding from the view to the component that captures user interactions. You can listen to any native DOM event like click, input, keyup, or mouseover.
<button (click)="handleClick($event)">Click Me</button>
<input (keyup.enter)="onEnter()" />
<div (mouseover)="onHover($event)">Hover me</div>

// Component class
export class AppComponent {
  handleClick(event: MouseEvent) {
    console.log('Clicked at:', event.clientX, event.clientY);
  }
  onEnter() { console.log('Enter pressed'); }
}
The special $event variable provides access to the raw DOM event object. Angular also supports key event filtering like (keyup.enter) and (keydown.escape) for cleaner event handling.

Two-way data binding synchronizes data between the component and the view in both directions simultaneously. The [(ngModel)] directive combines property binding and event binding into one syntax. When the user types in an input, the component property updates automatically and vice versa. You need to import FormsModule to use ngModel in your templates.
<!-- Requires FormsModule -->
<input [(ngModel)]="username" />
<p>Hello, {{ username }}</p>

<!-- Equivalent expanded form -->
<input [ngModel]="username" (ngModelChange)="username = $event" />
To use ngModel, import FormsModule in your module:
import { FormsModule } from '@angular/forms';
@NgModule({ imports: [FormsModule] })
export class AppModule { }
The banana-in-a-box syntax [()] is a shorthand combining property binding and event binding. For custom components, name the @Output as xChange to match the @Input x.

Why it matters: Tests understanding of two-way binding mechanics and the underlying pattern. Shows you know how Angular synchronizes component and view state.

Real applications: Form input fields synchronized with component properties, search boxes triggering real-time filtering, modal dialogs maintaining open/closed state bi-directionally.

Common mistakes: Developers forget to import FormsModule, causing ngModel to fail silently. They don't understand the banana-in-a-box is syntactic sugar. They try two-way binding on non-form elements inappropriately.

Property binding sets a DOM property, while attribute binding sets an HTML attribute. Most of the time they overlap, but some attributes have no corresponding DOM property like colspan and aria-*. Properties reflect the current state of the element while attributes reflect the initial HTML value. Use the [attr.name] prefix when binding to attributes that have no DOM property equivalent.
<!-- Property binding (sets the DOM property) -->
<input [value]="name" />

<!-- Attribute binding (sets the HTML attribute) -->
<td [attr.colspan]="colSpan">Merged</td>
<div [attr.aria-label]="label">Accessible</div>
<table>
  <tr [attr.data-id]="rowId">...</tr>
</table>
Property binding is the default and should be used in most cases. Use [attr.name] specifically for accessibility attributes, data attributes, and colspan where no DOM property exists.

Why it matters: Tests understanding of DOM properties vs HTML attributes distinction. Shows you know subtle HTML/DOM differences Angular developers must grasp.

Real applications: Bind aria-label for accessibility, colspan for table merging, data-* attributes for custom DOM data, disabled property (not attribute) for user interactions.

Common mistakes: Developers confuse properties and attributes, trying to bind to attribute values when the property exists. They don't realize some HTML attributes have no DOM property equivalent.

Angular provides shorthand syntax for binding CSS classes and inline styles to elements dynamically. You can toggle a single class with [class.name] or manage multiple classes with [ngClass]. Similarly, set individual styles with [style.prop] or multiple styles with [ngStyle]. These bindings update automatically when the component data changes.
<!-- Single class binding -->
<div [class.active]="isActive">Tab</div>

<!-- Multiple classes with ngClass -->
<div [ngClass]="{ 'active': isActive, 'disabled': isDisabled }">Item</div>

<!-- Single style binding -->
<div [style.color]="textColor">Styled</div>
<div [style.font-size.px]="fontSize">Sized</div>

<!-- Multiple styles with ngStyle -->
<div [ngStyle]="{ 'color': textColor, 'font-weight': isBold ? 'bold' : 'normal' }">Text</div>
Class binding toggles a single CSS class based on a boolean expression. Style binding sets individual style properties with optional unit suffixes like .px, .em, or .%.

Why it matters: Tests knowledge of dynamic CSS and styling in templates. Shows you can apply conditional styles without separate component logic.

Real applications: Toggle active tab classes, conditionally disable buttons, highlight error fields, dynamically set font sizes and colors based on data, apply theme classes.

Common mistakes: Developers try to use [class] instead of [class.name] for single classes. They don't know you can chain units like [style.width.px]. They use ngStyle for everything when simple class binding is better.

Template expressions are the code snippets inside interpolation {{ }} or binding brackets [ ] that Angular evaluates to produce a value. They are evaluated on every change detection cycle, so they should be simple and fast. The expression context is the component instance, so you can access properties and call methods directly. Template expressions should be side-effect free and return a value quickly.
<!-- Valid template expressions -->
<p>{{ user.name }}</p>
<p>{{ items.length > 0 ? 'Has items' : 'Empty' }}</p>
<p>{{ getTotal() }}</p>
<img [src]="getImageUrl(product.id)" />
Limitations: Template expressions cannot use assignments (=), the new keyword, chaining with semicolons, or increment/decrement operators. Keep expressions simple and move complex logic to the component class for better performance.

Why it matters: Tests understanding of Angular's template evaluation model and performance implications. Shows you know best practices for template expressions.

Real applications: Display formatted user names, show conditional messages based on object properties, call getter methods for derived values, compute display strings from data.

Common mistakes: Developers put complex calculations in templates, hurting performance. They use assignments or side effects in expressions. They don't realize expressions run on every change detection cycle.

The banana-in-a-box [( )] syntax is Angular's shorthand for two-way data binding. It combines property binding [] (the box) with event binding () (the banana) in one expression. The most common use is [(ngModel)] for form inputs to keep the view and model in sync. You can also create custom two-way bindings on your own components.
<!-- Two-way binding shorthand -->
<input [(ngModel)]="searchTerm" />

<!-- Custom two-way binding on a component -->
@Component({ selector: 'app-sizer', template: '...' })
export class SizerComponent {
  @Input() size!: number;
  @Output() sizeChange = new EventEmitter<number>();
  inc() { this.sizeChange.emit(this.size + 1); }
}

<!-- Usage -->
<app-sizer [(size)]="fontSize"></app-sizer>
For custom two-way binding, the convention is an @Input named x paired with an @Output named xChange. Angular automatically wires up the [( )] syntax when this naming convention is followed.

Why it matters: Tests understanding of how to create custom two-way binding patterns. Shows you control the banana-in-a-box syntax for your own components.

Real applications: Custom color picker components with two-way color binding, quantity selectors emitting size changes, dialog visibility controls with two-way open status.

Common mistakes: Developers name the @Output incorrectly (not using the xChange pattern), breaking the [(x)] syntax. They think banana-in-a-box only works with ngModel. They don't realize it's just syntactic sugar for [x]="value" and (xChange)="value=$event".

Angular provides the safe navigation operator ?. and the nullish coalescing operator ?? to handle null and undefined values gracefully in templates. Without these operators, accessing a property on a null object would throw a runtime error. The safe navigation operator short-circuits and returns undefined instead of crashing the template. The nullish coalescing operator provides a default value when the expression is null or undefined.
<!-- Safe navigation operator prevents errors on null -->
<p>{{ user?.address?.city }}</p>

<!-- Nullish coalescing provides defaults -->
<p>{{ username ?? 'Guest' }}</p>

<!-- Without safe navigation, this throws if user is null -->
<!-- <p>{{ user.name }}</p>  ERROR -->

<!-- Combining with ngIf for conditional rendering -->
<div *ngIf="user">
  <p>{{ user.name }}</p>
</div>
The safe navigation operator is especially useful when data loads asynchronously from APIs. Combined with *ngIf, you can handle loading states cleanly without risking template errors.

Why it matters: Tests understanding of null safety in templates and async data handling. Shows you can prevent template errors gracefully.

Real applications: Accessing nested user properties when user data loads from API, displaying product details with safe navigation on optional fields, rendering nested object trees safely.

Common mistakes: Developers forget the safe navigation operator and crash templates when async data hasn't loaded yet. They use verbose *ngIf checks instead of the concise ?. operator. They confuse ?? (nullish coalescing) with || (logical OR).

One-way data binding flows data in a single direction — either from the component to the view using interpolation or property binding, or from the view to the component using event binding. Two-way data binding flows data in both directions simultaneously using the [(ngModel)] syntax. One-way binding is more predictable and easier to debug because data flows in one direction. Two-way binding is convenient for form inputs where you want the view and model to stay in sync.
<!-- One-way: component to view -->
<p>{{ message }}</p>
<img [src]="imageUrl" />

<!-- One-way: view to component -->
<button (click)="onClick()">Click</button>

<!-- Two-way: both directions -->
<input [(ngModel)]="name" />
One-way binding is preferred for most cases as it gives better control over data flow. Use two-way binding mainly for form inputs where automatic synchronization is needed.

Why it matters: Tests understanding of data flow architecture and when to use each pattern. Shows you know recommendations for maintainable code.

Real applications: Display-only values use one-way binding, forms use two-way binding, event handlers use event binding, and component communication uses property and @Output bindings.

Common mistakes: Developers overuse two-way binding everywhere. They use event binding when they should use property binding. They don't understand one-way binding is simpler and more predictable for debugging.

[class.className] is used to toggle a single CSS class based on a boolean condition. [ngClass] is used when you need to apply multiple classes dynamically using an object, array, or string expression. The single class binding is simpler and slightly more performant for toggling one class. Use ngClass when you have complex conditional logic with multiple classes.
<!-- Single class toggle -->
<div [class.active]="isActive">Single</div>

<!-- Multiple classes with ngClass -->
<div [ngClass]="{'active': isActive, 'disabled': isDisabled, 'highlight': isNew}">Multi</div>

<!-- Array syntax -->
<div [ngClass]="['base', isSpecial ? 'special' : 'normal']">Array</div>
Prefer [class.name] for simple single-class toggling as it is more readable. Use [ngClass] when you need to manage multiple dynamic classes based on different conditions.

Why it matters: Tests understanding of when to use different Angular directives for optimal performance and readability.

Real applications: Toggle active tab states, apply validation error classes, highlight selected items, apply theme classes conditionally, manage ui states visually.

Common mistakes: Developers always use ngClass even for single-class toggles. They try [class]="..." instead of [class.name]="...". They don't know [class..*] syntax exists for simple cases.

$event is a special variable in Angular event binding that contains the raw DOM event object for native events or the emitted value for custom events. For native events like click or input, $event gives you access to properties like target, clientX, and methods like preventDefault(). For custom @Output events, $event holds whatever value was passed to EventEmitter.emit(). It lets you access event details directly in the template.
<!-- Native DOM event: $event is MouseEvent -->
<button (click)="onClick($event)">Click</button>

<!-- Input event: access typed value -->
<input (input)="onInput($event)" />

<!-- Custom event: $event is the emitted value -->
<app-child (notify)="onNotify($event)"></app-child>
For native events, $event is the DOM event type like MouseEvent or KeyboardEvent. For custom component events, it is the type you pass to emit().

Why it matters: Tests understanding of how to access event data in event handlers. Shows knowledge of Angular event handling patterns.

Real applications: Prevent form submission on enter key, access form data from input events, pass custom event values from child components, handle mouse coordinates on click.

Common mistakes: Developers forget to pass $event to the handler. They don't know $event type differs between native and custom events. They try to access properties that don't exist on the event type.

Yes, you can use pipes inside interpolation and property binding expressions to transform displayed values. Pipes work in template expressions by using the pipe character (|) after the value. You can chain multiple pipes together and pass parameters using colons. However, pipes cannot be used inside event binding expressions because event bindings execute statements, not value expressions.
<!-- Pipe in interpolation -->
<p>{{ birthday | date:'fullDate' | uppercase }}</p>

<!-- Pipe in property binding -->
<p [textContent]="title | uppercase"></p>

<!-- Pipe with parameters -->
<p>{{ price | currency:'USD':'symbol':'1.2-2' }}</p>
Pipes are meant only for transforming output values for display. Keep pipe transforms pure and lightweight since they run on every change detection cycle.

Why it matters: Tests understanding of template transformations and when pipes are applicable. Shows you know formatting options for display.

Real applications: Format dates for display, convert text case for UI, format currency values, filter arrays, truncate text, apply custom transformations to data.

Common mistakes: Developers try to use pipes in event handlers or two-way bindings. They create impure pipes that modify data. They don't realize pipes run frequently and must be fast.

The safe navigation operator (?.) protects against null and undefined values when accessing properties of an object in templates. If any part of the property path is null or undefined, the expression short-circuits and returns undefined instead of throwing an error. It is extremely useful when working with data that loads asynchronously from APIs where objects might initially be null. This avoids the need for multiple *ngIf checks just to prevent template errors.
<!-- Without safe navigation: throws error if user is null -->
<!-- <p>{{ user.address.city }}</p> -->

<!-- With safe navigation: renders nothing if any part is null -->
<p>{{ user?.address?.city }}</p>
<p>{{ user?.orders?.[0]?.total }}</p>
Use the safe navigation operator for optional chaining in templates to prevent runtime errors. Combine it with *ngIf or the nullish coalescing operator ?? for complete null safety.

Why it matters: Tests knowledge of how to handle async data and null safety. Shows you can write robust templates that don't crash.

Real applications: Display user profile data that might be loading, access nested attributes safely, render API response values that might be null, handle optional user preferences.

Common mistakes: Developers forget the safe navigation operator and templates crash on null values. They use verbose *ngIf chains instead of the concise ?. operator. They don't combine it with nullish coalescing for better UX.