In-depth Guides
Template Syntax

Property binding best practices

By following a few guidelines, you can use property binding in a way that helps you reduce bugs and keep your code readable.

Avoid side effects

Evaluation of a template expression should have no visible side effects. Use the syntax for template expressions to help avoid side effects. In general, the correct syntax prevents you from assigning a value to anything in a property binding expression. The syntax also prevents you from using increment and decrement operators.

An example of producing side effects

If you had an expression that changed the value of something else that you were binding to, that change of value would be a side effect. Angular might or might not display the changed value. If Angular does detect the change, it throws an error.

As a best practice, use only properties and methods that return values.

Return the proper type

A template expression should result in the type of value that the target property expects. For example, return:

  • a string, if the target property expects a string
  • a number, if it expects a number
  • an object, if it expects an object.

Passing in a string

In the following example, the childItem property of the ItemDetailComponent expects a string.

src/app/app.component.html

      
<div>
<h1>Property Binding with Angular</h1>
<h2>Binding the src property of an image:</h2>
<img alt="item" [src]="itemImageUrl">
<hr />
<h2>Binding to the colSpan property</h2>
<table border=1>
<tr><td>Column 1</td><td>Column 2</td></tr>
<!-- Notice the colSpan property is camel case -->
<tr><td [colSpan]="2">Span 2 columns</td></tr>
</table>
<hr />
<h2>Button disabled state bound to isUnchanged property:</h2>
<!-- Bind button disabled state to `isUnchanged` property -->
<button type="button" [disabled]="isUnchanged">Disabled Button</button>
<hr />
<h2>Binding to a property of a directive</h2>
<p [ngClass]="classes">[ngClass] binding to the classes property making this blue</p>
<hr />
<h2>Model property of a custom component:</h2>
<app-item-detail [childItem]="parentItem"></app-item-detail>
<app-item-detail childItem="parentItem"></app-item-detail>
<h3>Pass objects:</h3>
<app-item-list [items]="currentItems"></app-item-list>
<hr />
<h2>Property binding and interpolation</h2>
<p><img alt="Interpolated item" src="{{ itemImageUrl }}"> is the <em>interpolated</em> image.</p>
<p><img alt="Property Bound item" [src]="itemImageUrl"> is the <em>property bound</em> image.</p>
<p><span>"{{ interpolationTitle }}" is the <em>interpolated</em> title.</span></p>
<p>"<span [innerHTML]="propertyTitle"></span>" is the <em>property bound</em> title.</p>
<hr />
<h2>Malicious content</h2>
<p><span>"{{ evilTitle }}" is the <em>interpolated</em> evil title.</span></p>
<!--
Angular generates a warning for the following line as it sanitizes them
WARNING: sanitizing HTML stripped some content (see https://g.co/ng/security#xss).
-->
<p>"<span [innerHTML]="evilTitle"></span>" is the <em>property bound</em> evil title.</p>
</div>

Confirm this expectation by looking in the ItemDetailComponent where the @Input() type is string:

src/app/item-detail.component.ts (setting the @Input() type)

      
import {Component, Input} from '@angular/core';
// import { Item } from '../item';
// import { ITEMS } from '../mock-items';
@Component({
standalone: true,
selector: 'app-item-detail',
template: `<p>Your item is: {{ childItem }} </p>`,
imports: [],
})
export class ItemDetailComponent {
@Input() childItem = '';
// items = ITEMS;
currentItem = 'bananas in boxes';
}

The parentItem in AppComponent is a string, which means that the expression, parentItem within [childItem]="parentItem", evaluates to a string.

src/app/app.component.ts

      
import {Component} from '@angular/core';
import {NgClass} from '@angular/common';
import {ItemDetailComponent} from './item-detail.component';
import {ItemListComponent} from './item-list.component';
@Component({
standalone: true,
selector: 'app-root',
templateUrl: './app.component.html',
imports: [ItemDetailComponent, ItemListComponent, NgClass],
styleUrls: ['./app.component.css'],
})
export class AppComponent {
itemImageUrl = '../assets/phone.svg';
isUnchanged = true;
classes = 'special';
parentItem = 'lamp';
currentItems = [
{
id: 21,
name: 'phone',
},
];
interpolationTitle = 'Interpolation';
propertyTitle = 'Property binding';
evilTitle = 'Template <script>alert("evil never sleeps")</script> Syntax';
}

If parentItem were some other type, you would need to specify childItem @Input() as that type as well.

Passing in an object

In this example, ItemListComponent is a child component of AppComponent and the items property expects an array of objects.

src/app/app.component.html

      
<div>
<h1>Property Binding with Angular</h1>
<h2>Binding the src property of an image:</h2>
<img alt="item" [src]="itemImageUrl">
<hr />
<h2>Binding to the colSpan property</h2>
<table border=1>
<tr><td>Column 1</td><td>Column 2</td></tr>
<!-- Notice the colSpan property is camel case -->
<tr><td [colSpan]="2">Span 2 columns</td></tr>
</table>
<hr />
<h2>Button disabled state bound to isUnchanged property:</h2>
<!-- Bind button disabled state to `isUnchanged` property -->
<button type="button" [disabled]="isUnchanged">Disabled Button</button>
<hr />
<h2>Binding to a property of a directive</h2>
<p [ngClass]="classes">[ngClass] binding to the classes property making this blue</p>
<hr />
<h2>Model property of a custom component:</h2>
<app-item-detail [childItem]="parentItem"></app-item-detail>
<app-item-detail childItem="parentItem"></app-item-detail>
<h3>Pass objects:</h3>
<app-item-list [items]="currentItems"></app-item-list>
<hr />
<h2>Property binding and interpolation</h2>
<p><img alt="Interpolated item" src="{{ itemImageUrl }}"> is the <em>interpolated</em> image.</p>
<p><img alt="Property Bound item" [src]="itemImageUrl"> is the <em>property bound</em> image.</p>
<p><span>"{{ interpolationTitle }}" is the <em>interpolated</em> title.</span></p>
<p>"<span [innerHTML]="propertyTitle"></span>" is the <em>property bound</em> title.</p>
<hr />
<h2>Malicious content</h2>
<p><span>"{{ evilTitle }}" is the <em>interpolated</em> evil title.</span></p>
<!--
Angular generates a warning for the following line as it sanitizes them
WARNING: sanitizing HTML stripped some content (see https://g.co/ng/security#xss).
-->
<p>"<span [innerHTML]="evilTitle"></span>" is the <em>property bound</em> evil title.</p>
</div>

In the ItemListComponent the @Input(), items, has a type of Item[].

src/app/item-list.component.ts

      
import {Component, Input} from '@angular/core';
import {NgFor} from '@angular/common';
import {ITEMS} from './mock-items';
import {Item} from './item';
@Component({
standalone: true,
selector: 'app-item-list',
template: `
<h4>Nested component's list of items:</h4>
<ul>
@for (item of listItems; track item) {
<li>{{item.id}} {{item.name}}</li>
}
</ul>
<h4>Pass an object from parent to nested component:</h4>
<ul>
@for (item of items; track item) {
<li>{{item.id}} {{item.name}}</li>
}
</ul>
`,
imports: [NgFor],
})
export class ItemListComponent {
listItems = ITEMS;
@Input() items: Item[] = [];
}

Notice that Item is an object and it has two properties, an id and a name.

src/app/item.ts

      
export interface Item {
id: number;
name: string;
}

In app.component.ts, currentItems is an array of objects in the same shape as the Item object in items.ts, with an id and a name.

src/app.component.ts

      
import {Component} from '@angular/core';
import {NgClass} from '@angular/common';
import {ItemDetailComponent} from './item-detail.component';
import {ItemListComponent} from './item-list.component';
@Component({
standalone: true,
selector: 'app-root',
templateUrl: './app.component.html',
imports: [ItemDetailComponent, ItemListComponent, NgClass],
styleUrls: ['./app.component.css'],
})
export class AppComponent {
itemImageUrl = '../assets/phone.svg';
isUnchanged = true;
classes = 'special';
parentItem = 'lamp';
currentItems = [
{
id: 21,
name: 'phone',
},
];
interpolationTitle = 'Interpolation';
propertyTitle = 'Property binding';
evilTitle = 'Template <script>alert("evil never sleeps")</script> Syntax';
}

By supplying an object in the same shape, you meet the expectations of items when Angular evaluates the expression currentItems.