Interpolation puts values into text. Two other bindings connect your class and your template in both directions: property binding sends values to elements, and event binding reports what the user did.
What you will learn
- How to set element properties with
[property] - How to bind classes and attributes
- How to react to clicks and typing with
(event)
Property binding
Square brackets around a property name mean "set this property from an expression in my class". A familiar example is an image address:
<img [src]="imageUrl" [alt]="imageAlt" width="120" />
The value inside the quotes is an expression, not text. Without the brackets, src="imageUrl" would look for a file literally named imageUrl.
You can bind many properties. Binding disabled is useful for forms and buttons:
<button [disabled]="isSaving">Save</button>
Class and attribute bindings
To switch a CSS class on or off, use [class.name]. For ARIA and other attributes that are not properties, use [attr.name]:
<button [class.liked]="liked" [attr.aria-pressed]="liked">Like</button>
You can also bind a single style, such as [style.color]="textColor".
Event binding
Parentheses around an event name mean "run this code when the event happens". The most common event is click:
<button (click)="toggle()">Like</button>
For events with data, such as typing, Angular provides the event object as $event. You can pass it to a method:
<input (input)="onType($event)" />
Put it together
This component uses all three kinds of binding:
// src/app/like-button/like-button.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-like-button',
template: `
<button type="button" [class.liked]="liked" [attr.aria-pressed]="liked" (click)="toggle()">
{{ liked ? 'Liked' : 'Like' }}
</button>
<img [src]="imageUrl" [alt]="imageAlt" width="64" />
<p>
<input [value]="draft" (input)="onType($event)" placeholder="Type something" />
</p>
<p>You typed: {{ draft }}</p>
`,
styles: `
.liked { background: #16a34a; color: white; }
`,
})
export class LikeButton {
protected liked = false;
protected draft = '';
protected readonly imageUrl = '/favicon.ico';
protected readonly imageAlt = 'Site icon';
protected toggle(): void {
this.liked = !this.liked;
}
protected onType(event: Event): void {
this.draft = (event.target as HTMLInputElement).value;
}
}
// src/app/app.ts
import { Component } from '@angular/core';
import { LikeButton } from './like-button/like-button';
@Component({
imports: [LikeButton],
selector: 'app-root',
templateUrl: './app.html',
styleUrl: './app.css',
})
export class App {}
<!-- src/app/app.html -->
<main>
<h1>Bindings</h1>
<app-like-button />
</main>
Click the button and the label and colour change. Type in the box and the text below follows. Here is what happens: the click calls toggle(), which changes liked, and Angular redraws the parts of the template that use it.
Which binding should I use?
- Data into text:
{{ value }} - Data into an element property:
[property]="value" - A user action out to your code:
(event)="method()"
Remember the direction. Square brackets go from the class to the template, parentheses go from the template to the class.
Common mistakes
- Brackets missing:
disabled="isSaving"always disables the button, because any text counts as true. Use[disabled]="isSaving". - Quotes inside quotes: inside a double-quoted binding use single quotes, such as
[class]="'big'". - Calling the handler without parentheses: write
(click)="toggle()", not(click)="toggle".
Try it yourself
- Add a button that clears the text box by setting
draftto an empty string. - Bind
[style.color]to red when the text is longer than 10 characters. - Disable the Like button once it has been liked, and add a second button that undoes it.
Quick check
- Which syntax sends a value from the class to an element property?
- What is
$event? - Why does
disabled="isSaving"not work as expected?
Next, continue with Angular Two-Way Binding: ngModel, ngModelChange and Input Events.