Interpolation
Angular template interpolation ({{ ... }}
) is the way of telling Angular to use data from the component class in the view.
Angular will keep track of the expression inside the curly braces and update the view whenever it considers it necessary.
Back to our previous example:
@Component({
selector: 'mc-greetings',
template: `<h1>Hello, {{ name }}!</h1>`,
})
class Greetings {
protected readonly name = '๐จโ๐ณ Younes';
}
Here, {{ name }}
is an interpolation. If the value of name
changes, Angular will automatically update the displayed text.
This is what we call one-way data binding. It's a binding from the component's state to the view.
You cannot use more complex ones such as multiple statements or assignments or try/catch blocks etc.
While expressions are powerful enough to express complex logic โ such as name && (friendlynessFactor ?? 0) > 0.5 ? name : 'Guest'
, I highly recommend to keep them simple and move complex logic out of templates.
What about security?โ
The results or expressions are HTML-escaped, therefore they are safe by design.
The following example:
@Component({
selector: 'mc-greetings',
template: `<h1>Hello, {{ name }}!</h1>`,
})
class Greetings {
protected readonly name = '<b>๐จโ๐ณ Younes</b>';
}
will produce the following output:
<h1>Hello <b>๐จโ๐ณ Younes</b>!</h1>
Interpolation does HTML-escaping, but depending on the context, you might need a different escaping.
Given the following unsafe example:
@Component({
selector: 'mc-user-profile-link',
template: `<a href="https://my-app.marmicode.io/users/{{ userId }}"
>Go to profile</a
>`,
})
class UserProfileLink {
/* ๐น Assuming `userId` is somehow controlled by the attacker.. */
protected readonly userId =
'../redirect?url=https://evil.marmicode.io/gotcha';
}
The result will be:
<a
href="https://my-app.marmicode.io/users/../redirect?url=https://evil.marmicode.io/gotcha"
>Go to profile</a
>
Clicking on the link will redirect the victim to https://evil.marmicode.io/gotcha
.
It is up to you to escape uncontrolled data when used in non-HTML contexts.
@Component({
selector: 'mc-user-profile-link',
template: `<a href="https://my-app.marmicode.io/users/{{ userId }}"
>Go to profile</a
>`,
})
class UserProfileLink {
/* ๐น Assuming `userId` is somehow controlled by the attacker.. */
protected readonly userId = encodeURIComponent(
'../redirect?url=https://evil.marmicode.io/gotcha',
);
}
Also, prefer property binding over interpolation when applicable.
@Component({
selector: 'mc-user-profile-link',
template: `<a [href]="getProfileUrl()">Go to profile</a>`,
})
class UserProfileLink {
/* ๐น Assuming `userId` is somehow controlled by the attacker.. */
protected readonly userId = encodeURIComponent(
'../redirect?url=https://evil.marmicode.io/gotcha',
);
getProfileUrl() {
return `https://my-app.marmicode.io/users/${encodeURIComponent(this.userId)}`;
}
}
This avoids simplifies the template, and guarantees proper escaping.