ProjectCore· 180 min read

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

Create the app, a component and a service
ng new task-app
cd task-app
ng g c task-list
ng g s task

Note: 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.

The service: load from the API, add locally
// 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.

The component injects the service and adds tasks
// 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.

The template: a form, an empty message, and the list
<!-- 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

  1. Create the app, the task-list component and the task service.
  2. Provide HttpClient in main.ts and import FormsModule so ngModel works.
  3. Load tasks from a public test API into the service and show them with *ngFor.
  4. Add a form that calls the service’s add() and clears the input.
  5. Show a “No tasks yet.” message with *ngIf when 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?

Answer: The service holds the shared task data and the load/add logic. The component injects it and just displays the list — exactly the split this course teaches.

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

  1. Add a “Clear all” button that empties the task list through a new service method.
  2. Use the titlecase pipe so every task title displays neatly.

🏠 Homework

  1. Extend the app so each task shows “done” or “pending”, with a button that toggles a task’s done value.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →