Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Impara Adding Functionality to Our Application | Services and Dependency Injection in Angular
Introduction to Angular
course content

Contenuti del Corso

Introduction to Angular

Introduction to Angular

1. Angular Fundamentals
2. Components and Templates
3. Mastering Angular Directives and Pipes
4. Services and Dependency Injection in Angular
5. Standalone Components & Modules
6. Routing and Navigation in Angular

book
Adding Functionality to Our Application

At this stage, our application already knows how to display a list of tasks and show a message when there are none. However, users still do not have a way to enter new tasks.

We will add the ability to create a new task using a convenient button and a modal form.

We will implement:

  • A stylish Add button;

  • A modal window with an input field for the task title;

  • The logic for adding a task to the list in the TaskService;

  • Automatic generation of a unique identifier.

Getting Started

The first thing we need to do is enhance our TaskService so it can create and store new tasks. The service should not only store tasks, but also handle all the business logic related to them.

We will create an addTask method in the service. The generation of a unique ID, creation of the task object, and saving it to the list will all happen inside the service. The method will only receive a title, which will be passed from the TaskListComponent.

ts

task-service

copy
1234567891011121314151617181920212223242526272829303132333435363738394041
import { Injectable } from '@angular/core'; export interface Task { id: number; title: string; completed: boolean; } @Injectable({ providedIn: 'root' }) export class TaskService { private tasks: Task[] = [ { id: 1, title: 'Buy groceries', completed: false }, { id: 2, title: 'Walk the dog', completed: true }, { id: 3, title: 'Learn Angular', completed: false } ]; getTasks(): Task[] { return [...this.tasks]; } addTask(title: string) { const maxId = this.tasks.length > 0 ? Math.max(...this.tasks.map(t => t.id)) : 0; const newTask: Task = { id: maxId + 1, title: title, completed: false, }; this.tasks.push(newTask); } deleteTask(id: number) { this.tasks = this.tasks.filter(task => task.id !== id); } toggleTaskStatus(id: number) { const task = this.tasks.find(t => t.id === id); if (task) task.completed = !task.completed; } }

The addTask() method takes only the task title and creates the Task object internally. It first finds the maximum ID among the existing tasks, then adds 1 to it to generate a unique identifier. The new task is always set as incomplete (completed: false) and is immediately added to the tasks array.

This approach eliminates unnecessary logic from the component and makes the service both self-sufficient and reusable.

Updating the TaskListComponent

Now that all the logic for creating a new task has been moved into the service, the component is only responsible for receiving user input, sending the task title to the service, and refreshing the local task list. This approach simplifies the component and centralizes business logic in the TaskService.

Inside the component, we will add two variables:

  • showAddTask — a flag that controls the visibility of the modal window for adding a task;

  • newTaskTitle — a string to hold the task title input from the user.

We will also implement the addTask() method, which:

  1. Checks that the input string is not empty;

  2. Passes the task title to the addTask(title: string) method of the service;

  3. Refreshes the local task list;

  4. Clears the input field and closes the modal window.

ts

task-component

copy
123456789101112131415161718192021222324252627282930313233343536
@Component({ selector: 'app-task-list', imports: [TaskComponentComponent, CommonModule, FormsModule], templateUrl: './task-list.component.html', styleUrl: './task-list.component.css' }) export class TaskListComponent { tasks: Task[] = []; showAddTask = false; newTaskTitle = ''; constructor(private taskService: TaskService) { this.tasks = this.taskService.getTasks(); } addTask() { const title = this.newTaskTitle.trim(); if (title) { this.taskService.addTask(title); this.tasks = this.taskService.getTasks(); this.newTaskTitle = ''; this.showAddTask = false; } } deleteTask(id: number) { this.taskService.deleteTask(id); this.tasks = this.taskService.getTasks(); } toggleStatus(id: number) { this.taskService.toggleTaskStatus(id); this.tasks = this.taskService.getTasks(); } }

The addTask() method is now as simple as possible: it only handles user interaction and delegates all business logic to the service. This makes the code easier to maintain and test.

Also, make sure that FormsModule is imported in your module, as it is necessary for two-way data binding with newTaskTitle.

Add Button and Modal Window

Now, let's add the UI part: the Add button and the HTML markup for the modal window that includes the input field and buttons.

html

task-component

css

component-style

copy
12345678910111213141516171819202122232425262728293031
<div class="task-list-container"> <div class="header"> <h2>My Tasks</h2> <button class="add-button" (click)="showAddTask = true"> <span>+</span> Add </button> </div> <div class="modal-backdrop" *ngIf="showAddTask"> <div class="modal"> <h3>Add New Task</h3> <input type="text" placeholder="Task title" [(ngModel)]="newTaskTitle" /> <div class="modal-buttons"> <button class="save-button" (click)="addTask()">Save</button> <button class="cancel-button" (click)="showAddTask = false">Cancel</button> </div> </div> </div> <div *ngIf="tasks.length > 0; else noTasks"> <task-component *ngFor="let task of tasks" [task]="task" (onDelete)="deleteTask($event)" (onToggle)="toggleStatus($event)"> </task-component> </div> <ng-template #noTasks> <div class="no-tasks">No tasks yet 😊</div> </ng-template> </div>

When the user clicks the Add button, the showAddTask variable becomes true, and the modal window appears. The input field is bound to the newTaskTitle variable via [(ngModel)], and the button actions either save the task or close the modal without changes.

Users will be able to conveniently add tasks through a modal form. The new task immediately appears in the list without requiring a page refresh.

We have now implemented interactivity that makes our application full-featured and user-friendly for everyday use.

Tutto è chiaro?

Come possiamo migliorarlo?

Grazie per i tuoi commenti!

Sezione 4. Capitolo 4

Chieda ad AI

expand
ChatGPT

Chieda pure quello che desidera o provi una delle domande suggerite per iniziare la nostra conversazione

course content

Contenuti del Corso

Introduction to Angular

Introduction to Angular

1. Angular Fundamentals
2. Components and Templates
3. Mastering Angular Directives and Pipes
4. Services and Dependency Injection in Angular
5. Standalone Components & Modules
6. Routing and Navigation in Angular

book
Adding Functionality to Our Application

At this stage, our application already knows how to display a list of tasks and show a message when there are none. However, users still do not have a way to enter new tasks.

We will add the ability to create a new task using a convenient button and a modal form.

We will implement:

  • A stylish Add button;

  • A modal window with an input field for the task title;

  • The logic for adding a task to the list in the TaskService;

  • Automatic generation of a unique identifier.

Getting Started

The first thing we need to do is enhance our TaskService so it can create and store new tasks. The service should not only store tasks, but also handle all the business logic related to them.

We will create an addTask method in the service. The generation of a unique ID, creation of the task object, and saving it to the list will all happen inside the service. The method will only receive a title, which will be passed from the TaskListComponent.

ts

task-service

copy
1234567891011121314151617181920212223242526272829303132333435363738394041
import { Injectable } from '@angular/core'; export interface Task { id: number; title: string; completed: boolean; } @Injectable({ providedIn: 'root' }) export class TaskService { private tasks: Task[] = [ { id: 1, title: 'Buy groceries', completed: false }, { id: 2, title: 'Walk the dog', completed: true }, { id: 3, title: 'Learn Angular', completed: false } ]; getTasks(): Task[] { return [...this.tasks]; } addTask(title: string) { const maxId = this.tasks.length > 0 ? Math.max(...this.tasks.map(t => t.id)) : 0; const newTask: Task = { id: maxId + 1, title: title, completed: false, }; this.tasks.push(newTask); } deleteTask(id: number) { this.tasks = this.tasks.filter(task => task.id !== id); } toggleTaskStatus(id: number) { const task = this.tasks.find(t => t.id === id); if (task) task.completed = !task.completed; } }

The addTask() method takes only the task title and creates the Task object internally. It first finds the maximum ID among the existing tasks, then adds 1 to it to generate a unique identifier. The new task is always set as incomplete (completed: false) and is immediately added to the tasks array.

This approach eliminates unnecessary logic from the component and makes the service both self-sufficient and reusable.

Updating the TaskListComponent

Now that all the logic for creating a new task has been moved into the service, the component is only responsible for receiving user input, sending the task title to the service, and refreshing the local task list. This approach simplifies the component and centralizes business logic in the TaskService.

Inside the component, we will add two variables:

  • showAddTask — a flag that controls the visibility of the modal window for adding a task;

  • newTaskTitle — a string to hold the task title input from the user.

We will also implement the addTask() method, which:

  1. Checks that the input string is not empty;

  2. Passes the task title to the addTask(title: string) method of the service;

  3. Refreshes the local task list;

  4. Clears the input field and closes the modal window.

ts

task-component

copy
123456789101112131415161718192021222324252627282930313233343536
@Component({ selector: 'app-task-list', imports: [TaskComponentComponent, CommonModule, FormsModule], templateUrl: './task-list.component.html', styleUrl: './task-list.component.css' }) export class TaskListComponent { tasks: Task[] = []; showAddTask = false; newTaskTitle = ''; constructor(private taskService: TaskService) { this.tasks = this.taskService.getTasks(); } addTask() { const title = this.newTaskTitle.trim(); if (title) { this.taskService.addTask(title); this.tasks = this.taskService.getTasks(); this.newTaskTitle = ''; this.showAddTask = false; } } deleteTask(id: number) { this.taskService.deleteTask(id); this.tasks = this.taskService.getTasks(); } toggleStatus(id: number) { this.taskService.toggleTaskStatus(id); this.tasks = this.taskService.getTasks(); } }

The addTask() method is now as simple as possible: it only handles user interaction and delegates all business logic to the service. This makes the code easier to maintain and test.

Also, make sure that FormsModule is imported in your module, as it is necessary for two-way data binding with newTaskTitle.

Add Button and Modal Window

Now, let's add the UI part: the Add button and the HTML markup for the modal window that includes the input field and buttons.

html

task-component

css

component-style

copy
12345678910111213141516171819202122232425262728293031
<div class="task-list-container"> <div class="header"> <h2>My Tasks</h2> <button class="add-button" (click)="showAddTask = true"> <span>+</span> Add </button> </div> <div class="modal-backdrop" *ngIf="showAddTask"> <div class="modal"> <h3>Add New Task</h3> <input type="text" placeholder="Task title" [(ngModel)]="newTaskTitle" /> <div class="modal-buttons"> <button class="save-button" (click)="addTask()">Save</button> <button class="cancel-button" (click)="showAddTask = false">Cancel</button> </div> </div> </div> <div *ngIf="tasks.length > 0; else noTasks"> <task-component *ngFor="let task of tasks" [task]="task" (onDelete)="deleteTask($event)" (onToggle)="toggleStatus($event)"> </task-component> </div> <ng-template #noTasks> <div class="no-tasks">No tasks yet 😊</div> </ng-template> </div>

When the user clicks the Add button, the showAddTask variable becomes true, and the modal window appears. The input field is bound to the newTaskTitle variable via [(ngModel)], and the button actions either save the task or close the modal without changes.

Users will be able to conveniently add tasks through a modal form. The new task immediately appears in the list without requiring a page refresh.

We have now implemented interactivity that makes our application full-featured and user-friendly for everyday use.

Tutto è chiaro?

Come possiamo migliorarlo?

Grazie per i tuoi commenti!

Sezione 4. Capitolo 4
Siamo spiacenti che qualcosa sia andato storto. Cosa è successo?
some-alt