Build a complete task manager from scratch — a real-world project that covers the full Angular development workflow.
ng new task-manager --routing --style=scss
cd task-manager
npm install @angular/material @angular/cdk @ngrx/signals
ng add @angular/material
// stores/task.store.ts
export const TaskStore = signalStore(
{ providedIn: 'root' },
withState({
tasks: [] as Task[],
loading: false,
filter: 'all' as 'all' | 'active' | 'completed',
}),
withEntities<Task>(),
withComputed(({ tasks, filter }) => ({
visibleTasks: computed(() => {
const f = filter();
return tasks().filter(t =>
f === 'all' ? true :
f === 'active' ? !t.completed :
t.completed
);
}),
completedCount: computed(() => tasks().filter(t => t.completed).length),
})),
withMethods((store, taskService = inject(TaskService)) => ({
loadTasks: rxMethod<void>(
pipe(
tap(() => patchState(store, { loading: true })),
switchMap(() => taskService.getAll().pipe(
tapResponse({
next: tasks => patchState(store, setAllEntities(tasks), { loading: false }),
error: () => patchState(store, { loading: false }),
})
))
)
),
toggleTask(id: number): void {
patchState(store, updateEntity({ id, changes: t => ({ completed: !t.completed }) }));
taskService.toggle(id).subscribe();
},
}))
);
<!-- task-list.component.html -->
<ul cdkDropList (cdkDropListDropped)="onReorder($event)">
@for (task of store.visibleTasks(); track task.id) {
<li cdkDrag [class.done]="task.completed">
<mat-checkbox [checked]="task.completed"
(change)="store.toggleTask(task.id)">
{{ task.title }}
</mat-checkbox>
<span class="priority {{ task.priority }}">{{ task.priority }}</span>
<button mat-icon-button (click)="store.deleteTask(task.id)">
<mat-icon>delete</mat-icon>
</button>
</li>
}
</ul>
// server/routes/tasks.js
router.get('/:userId/tasks', authMiddleware, async (req, res) => {
const tasks = await Task.find({ userId: req.params.userId }).sort({ order: 1 });
res.json(tasks);
});
router.post('/:userId/tasks', authMiddleware, async (req, res) => {
const task = await Task.create({ ...req.body, userId: req.params.userId });
res.status(201).json(task);
});
All Comments