One card is a design. The tracker needs one per habit, drawn from data. The data is a signal and
the cards come from @for, as in any Angular app. The part worth knowing is what that turns into
on a phone.
Keep the habits in a signal, and draw the card for each:
import { Component, signal } from '@angular/core';
interface Habit {
readonly id: string;
readonly name: string;
readonly done: boolean;
}
export class App {
protected readonly habits = signal<readonly Habit[]>([
{ id: 'water', name: 'Drink water', done: false },
{ id: 'read', name: 'Read ten pages', done: false },
{ id: 'walk', name: 'Walk', done: true },
]);
}
@for (habit of habits(); track habit.id) {
<view class="habit">
<text>{{ habit.name }}</text>
<text class="status">To do</text>
</view>
}
Every card is a set of native views, created when its habit appears and destroyed when it goes.
A stable, unique id lets Angular keep the views of a row it already has when the list changes,
and move them when the list is reordered, rather than tear them down and build them again, which
on a phone is the expensive part. Names make poor keys, because they can change and they can
repeat: two tracked rows with the same key leave Angular unable to tell which is which.