Templates & Interpolation
A template is the HTML of a component, extended with Angular syntax. Plain HTML can only show fixed text; a template can show values from the component class, react to events and repeat or hide parts of the page.
In this lesson you will learn interpolation, the simplest way to print data, and what kinds of expressions you can write inside a template.
Interpolation with {{ }}
Double curly braces print the result of an expression as text. Angular reads the expression in the context of the component instance, so names refer to the class's fields and methods.
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-bill',
template: `
<h2>Bill for {{ student.name }}</h2>
<p>Items: {{ items().length }}</p>
<p>Total: ₹{{ price() * quantity() }}</p>
<p>{{ greet('Meera') }}</p>
`,
})
export class Bill {
protected student = { name: 'Farhan' };
protected items = signal(['Idli', 'Vada', 'Chai']);
protected price = signal(40);
protected quantity = signal(3);
protected greet(name: string) {
return `Hello, ${name}!`;
}
}Bill for Farhan Items: 3 Total: ₹120 Hello, Meera!
Notice the brackets after items(), price() and quantity(). These fields are signals, and you read a signal by calling it like a function. Plain fields such as student are read without brackets. You will learn signals properly in Signals & computed.
Whenever a signal used in the template changes, Angular updates just the text that depends on it.
What you can write in an expression
Template expressions look like JavaScript, but they are a smaller, safer language. Things you can use:
- Property access and method calls:
student.name,greet('Meera') - Arithmetic and comparison:
price() * quantity(),marks() >= 33 - The conditional operator:
{{ quantity() > 1 ? 'plates' : 'plate' }} - Logical operators
&&,||,!and nullish coalescing?? - Optional chaining
?.for values that may be missing - Array and object literals, the exponent operator
**,typeof, and untagged template strings with backticks
Here is a second example that uses several of these:
@Component({
selector: 'app-room-info',
template: `
<p>{{ quantity() > 1 ? 'plates' : 'plate' }}</p>
<p>Room: {{ student.hostel?.room ?? 'Day scholar' }}</p>
<p>{{ \`Token \${token()} is ready\` }}</p>
`,
})
export class RoomInfo {
protected student: { name: string; hostel?: { room: number } } = { name: 'Isha' };
protected quantity = signal(2);
protected token = signal(17);
}plates Room: Day scholar Token 17 is ready
student.hostel?.room stops safely and gives undefined when hostel is missing, instead of throwing an error, and ?? then supplies the fallback text. (The backslashes in the third line are only needed because this template is itself inside a TypeScript template string; in a separate .html file you write the backticks and ${} directly.)
What you cannot write
Templates are for displaying data, so some JavaScript is not allowed:
- Assignments such as
count = 5, and++,--,+= - The
newkeyword, and statements separated by; - Global objects such as
Math,window,consoleorJSON, because only the component's members are in scope
If you try, the build stops. For example:
X [ERROR] TS2339: Property 'Math' does not exist on type 'Bill'. X [ERROR] NG5002: Parser Error: Bindings cannot contain assignments at column 10 in [ count = 5 ]
When you need such logic, put it in the class (for example a method or a computed signal) and call that from the template.
Local variables with @let
The @let block declares a read-only variable inside a template. It is useful when the same value is needed in several places:
@let subtotal = price() * quantity();
@let gst = subtotal * 0.05;
<p>Subtotal: ₹{{ subtotal }}</p>
<p>GST (5%): ₹{{ gst }}</p>
<p>Pay: ₹{{ subtotal + gst }}</p>Subtotal: ₹120 GST (5%): ₹6 Pay: ₹126
A @let value is recalculated whenever the values it uses change. You cannot assign to it again in the template.
Interpolation is safe by default
Interpolation always inserts text, never HTML. If a field holds '<b>Pay at counter</b>', the page shows the angle brackets literally instead of bold text. This automatic escaping protects your app from cross-site scripting (XSS), an attack where someone sneaks a script into data that a page later displays.
Some characters have special meaning in templates. To show a literal curly brace, write {{ '{' }} or the HTML entity { (and } for }). If the compiler ever reads an @ in your text as the start of a block, write it as @.
Keep expressions quick
Angular evaluates template expressions often, every time it checks the component. Expressions should be fast and must not change anything (no side effects). Calling a method that loops over thousands of items or makes an HTTP request in a template slows the app down and can cause bugs. Use a computed signal for derived values; it only recalculates when its inputs change.
Common mistakes
- Forgetting the brackets on a signal.
{{ price }}does not print the number, and the compiler warns:NG8109: price is a function and should be invoked: price(). Write{{ price() }}. - Making template-only members
public. Mark themprotectedso the template can use them but other classes cannot. - Putting business logic in templates. Long conditions in
{{ }}are hard to read and test. Move them to the class. - Trying to render HTML strings with interpolation. It shows the tags as text, on purpose. Build the structure in the template instead.
Key points
{{ expression }}prints the result of an expression as text, using the component's members.- Read signals by calling them:
{{ total() }}; read plain fields without brackets. - Expressions support operators,
?.,??, the conditional operator and template strings, but not assignments,newor globals such asMath. @let name = expression;creates a read-only local variable in the template.- Interpolation escapes HTML automatically, which protects against XSS.
Exercise
Create a component ResultCard with signals studentName ("Rohan"), marks (412) and maxMarks (500). In the template, show the name, the marks as "412 / 500", the percentage using a @let variable, and the word "Pass" or "Fail" (pass is 33% or more). Do the rounding of the percentage in a class method, not with Math in the template.
Show solution
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-result-card',
template: `
@let percent = toPercent(marks(), maxMarks());
<h2>{{ studentName() }}</h2>
<p>Marks: {{ marks() }} / {{ maxMarks() }}</p>
<p>Percentage: {{ percent }}%</p>
<p>Result: {{ percent >= 33 ? 'Pass' : 'Fail' }}</p>
`,
})
export class ResultCard {
protected studentName = signal('Rohan');
protected marks = signal(412);
protected maxMarks = signal(500);
protected toPercent(got: number, max: number) {
return Math.round((got / max) * 1000) / 10;
}
}The page shows Percentage: 82.4% and Result: Pass. Math is fine inside the class, where normal TypeScript rules apply.
Quick Quiz
1. How do you print the value of a signal called total in a template?
A signal is read by calling it like a function.
2. Which of these is NOT allowed in a template expression?
Template expressions cannot contain assignments; change state in event handlers or class methods.
3. A field contains '<i>Hi</i>'. What does {{ field }} show?
Interpolation escapes HTML so it is shown as text, which prevents XSS.
4. What does @let gst = subtotal * 0.05; do?
@let declares a local, read-only variable inside the template.
Learn Angular with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
