Project: Build a Task List App
Put it all together: a single-page task list with a service, an API call, *ngFor and a form to add tasks.
What you will learn
- Combine components, a service and HttpClient
- Display a list with *ngFor and add items with a form
- Build a complete, working Angular app
What you will build
A small but complete task list app. It loads tasks from an API into a service, shows them with *ngFor, and lets the user add a new task with a form. This uses almost every idea from the course in one place.
Step 1 — Create the project and a component
ng new task-app
cd task-app
ng g c task-list
ng g s taskNote: Output:
CREATE src/app/task-list/...
CREATE src/app/task.service.ts
You now have a project, a task-list component for the screen, and a task service for the data and logic.
Step 2 — The service loads and stores tasks
The service fetches tasks from an API with HttpClient and keeps the list. It also offers an add method.
// src/app/task.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class TaskService {
tasks: any[] = [];
constructor(private http: HttpClient) {}
load() {
this.http.get('https://example.com/api/tasks')
.subscribe(data => this.tasks = data as any[]);
}
add(title: string) {
this.tasks.push({ title: title, done: false });
}
}Note: Output:
(No visible output here — this is the data layer.)
load() fills tasks from the server when it replies; add() pushes a new task onto the same shared list that the component shows.
Step 3 — The component shows the list and a form
The component injects the service, calls load() on start, lists tasks with *ngFor, and uses ngModel for the new-task input.
// src/app/task-list/task-list.component.ts
import { Component } from '@angular/core';
import { TaskService } from '../task.service';
@Component({
selector: 'app-task-list',
templateUrl: './task-list.component.html'
})
export class TaskListComponent {
newTitle = '';
constructor(public taskService: TaskService) {
this.taskService.load(); // fetch tasks at startup
}
addTask() {
if (this.newTitle.trim()) {
this.taskService.add(this.newTitle);
this.newTitle = ''; // clear the box
}
}
}Note: Output:
(No visible output by itself — this is the logic layer.)
The component asks Angular for the TaskService, calls load() once at startup, and offers addTask() which adds the typed title (when it is not blank) and clears the box. The template below renders all of this.
<!-- task-list.component.html -->
<h1>My Tasks</h1>
<form (ngSubmit)="addTask()">
<input [(ngModel)]="newTitle" name="newTitle"
placeholder="New task">
<button type="submit">Add</button>
</form>
<p *ngIf="taskService.tasks.length === 0">No tasks yet.</p>
<ul>
<li *ngFor="let task of taskService.tasks; let i = index">
{{ i + 1 }}. {{ task.title }}
</li>
</ul>Note: Output (after the API replies and you add one task):
My Tasks
[ New task ] [Add]
1. Buy milk
2. Walk dog
3. Finish homework
4. Call dentist
The first three came from the API via the service; “Call dentist” is the one you typed and added. The *ngIf message only appears when the list is empty.
Your tasks
- Create the app, the
task-listcomponent and thetaskservice. - Provide HttpClient in
main.tsand import FormsModule songModelworks. - Load tasks from a public test API into the service and show them with
*ngFor. - Add a form that calls the service’s
add()and clears the input. - Show a “No tasks yet.” message with
*ngIfwhen the list is empty.
Watch out: Remember the two setup steps that trip people up: provideHttpClient() in main.ts for the API call, and FormsModule in the component’s imports for ngModel. Missing either gives a clear error in the console.
Tip: Build in small steps and check the browser after each one: first show a hard-coded list, then wire the form, then connect the real API. A small working app beats a big broken one.
Q. In this project, why does the task list live in a service instead of the component?
Note: When this runs you have built a real single-page app using components, a service, dependency injection, HttpClient, *ngFor, *ngIf and two-way binding — the core of professional Angular work. Add it to your portfolio!
✍️ Practice
- Add a “Clear all” button that empties the task list through a new service method.
- Use the
titlecasepipe so every task title displays neatly.
🏠 Homework
- Extend the app so each task shows “done” or “pending”, with a button that toggles a task’s
donevalue.