Angular 19.1.6 introduces track expression requiring temporary variables feature where @for
's tracking expression can use coalesce (??) or logical (||) operator. It is useful when the previous value is null or undefined, and the next defined value is used to identify the array item.
In this demo, I define an Address type that consists of postal code and zip properties. The type of both fields is string | undefined
. This is because the US address only has a zip code, a Canadian address only has a postal code, and a Hong Kong address has neither. The properties are mutually exclusive. When rendering an address array, @for
's tracking expression comprises the zip and postal code to track the data row.
Data Type
// address.type.ts
export type Address = {
line1: string;
zip?: string;
postalCode?: string;
city: string;
country: string;
}
The type has required line1
, city
, and country
while zip
and postalCode
are optional properties.
Sample Data
import { Address } from "./address.type";
export const addresses: Address[] = [
{
line1: 'Address 1',
zip: '123456',
city: 'New York',
country: 'United States of America'
},
{
line1: '150 Graydon Hall Drive',
postalCode: 'M3A3B1',
city: 'North York',
country: 'Canada'
},
{
line1: '150 Nathan Road',
city: 'Mong Kok',
country: 'Hong Kong'
},
{
line1: '1 Middle Road',
city: 'Tsim Sha Road',
country: 'Hong Kong'
},
{
line1: '197 Yonge Street, Massey Tower',
postalCode: 'M5B0C1',
city: 'Toronto',
country: 'Canada'
}
];
The addresses array includes addresses in the USA, Canada, and Hong Kong. Since Hong Kong does not have a zip or postal code, I use the line1 field to track the array items.
Next, I can create a @for
block in the inline template to display the data.
Initialize components with the array
// address-list.component.ts
@Component({
selector: 'app-address-list',
imports: [AddressItem],
template: `
@for (address of addresses(); track address.zip || address.postalCode || address.line1) {
<app-address-item [address]="address" />
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AddressList {
addresses = input<Address[]>([]);
}
The tracking expression is address.zip || address.postalCode || address.line1
. When the zip
value is defined, Angular uses it for tracking. When zip
is undefined, and the postal code
has value, postal
code is the key to identify the array item. When both zip
and postalCode
are undefined, the key of that item is line1
, which is always not blank.
@Component({
selector: 'app-root',
imports: [AddressList],
template: `
<app-address-list [addresses]="addresses"/>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class App {
addresses = addresses;
}
The AppComponent
imports the addresses
array and passes it to the AddressList
component as input. The AddresssList
component finally loops the array to render the values.
Tip: The rows in the address array have unique zip, postal code, and line1. Therefore, address.zip || address.postalCode || address.line1
is a unique composite key. In a real-world application, these properties can easily have duplicate values in a database; therefore, the items should have unique IDs to distinguish them.
Top comments (0)