Add a Task with HTTP Client
Chapter Objectives
- ✔️Create a task using HTTP ClientAdd a task to the list by making an API call to the mock server.
TaskService
You’ve just communicated with the API server to retrieve a list of tasks. Now update the list stored in the mock API by adding a new task.
Based on the HTTP protocol, you’ll use the post function to add a task to the list: http.post(). This function expects 2 parameters:
- The API server URL
- The task data to send to the server
addTask(task: TaskForm) { return this.http.post<Task>('http://localhost:3000/tasks', { ...task, createdAt: new Date() });}
Since JSON-server is capable of generating an id for us, you won’t use the uuid package to generate an id for the task.
This new addTask function defines the exchange with the API server:
- It makes a POST request;
- It sends a TaskForm object as the request body;
- It communicates with the API server at the address
http://localhost:3000/tasks
.
🎓 Instructions
-
Modify the file
src/app/task.service.ts
.import { Injectable } from "@angular/core";import { HttpClient } from "@angular/common/http";import { Task, TaskForm } from "./task.model";@Injectable({providedIn: "root",})export class TaskService {constructor(private http: HttpClient) {}addTask(task: TaskForm) {return this.http.post<Task>("http://localhost:3000/tasks", {...task,createdAt: new Date(),});}}
Modify TaskFormComponent
In the previous step, you learned that observables must be subscribed to execute the request. You were able to use the async pipe in the HTML Template to subscribe to the observable.
But in the current situation, the request occurs in the component.ts
file.
Let’s subscribe to the observable using the subscribe
function.
🎓 Instructions
-
Modify the file
src/app/task-form/task-form.component.ts
.import { Component } from '@angular/core';import { TaskService } from '../task.service';import { TaskForm } from '../task.model';@Component({selector: 'app-task-form',templateUrl: './task-form.component.html',styleUrls: ['./task-form.component.css']})export class TaskFormComponent {task: TaskForm = {title: '',description: ''};constructor(private taskService: TaskService) { }submit() {const id = this.route.snapshot.paramMap.get('id');if (id) {const existingTask = this.taskService.getTask(id);this.taskService.updateTask({...existingTask,...this.task});} else {this.taskService.addTask(this.task).subscribe();}this.router.navigate(['/']);}}
This works now, but not exactly as you’d want it to…
Asynchronous Programming
Remember the newspaper example from the previous chapter? Since it’s a physical newspaper, its delivery to your mailbox takes time. Some time passes between when you subscribe and when you receive the newspaper.
It’s the same in our situation. By sending a request with the subscribe() function, you’re asking the server to add a task to the list. But the navigation to the ”/” route will happen immediately after sending the request, not once the request is complete.
Let’s review the code you just modified in the submit
function of TaskFormComponent
:
submit() { const id = this.route.snapshot.paramMap.get('id');
if (id) { const existingTask = this.taskService.getTask(id); this.taskService.updateTask({ ...existingTask, ...this.task }); } else { this.taskService.addTask(this.task).subscribe(); } this.router.navigate(['/']);}
- You call the addTask function from TaskService to add a task to the API server.
- You navigate to the ”/” route.
API communication is asynchronous, which means the addTask function’s action might not be resolved yet when the router.navigate function is called. Our server runs locally, so the request will be fast, but it’s still asynchronous.
A request to the server can take a long time if the server or network is slow for any reason. In this situation, while the request is still processing, the router.navigate function will be executed.
This isn’t what you want because when navigating, you want to display the updated task list.
You need to wait for the server’s response before navigating to the ”/” route.
The Subscription
The subscribe function accepts a callback function as a parameter. This callback function will be executed when the observable emits a value.
Use this callback function to navigate to the ”/” route.
🎓 Instructions
-
Modify the file
src/app/task-form/task-form.component.ts
.import { Component } from '@angular/core';import { Router } from '@angular/router';import { TaskService } from '../task.service';import { TaskForm } from '../task.model';@Component({selector: 'app-task-form',templateUrl: './task-form.component.html',styleUrls: ['./task-form.component.css']})export class TaskFormComponent {task: TaskForm = {title: '',description: ''};constructor(private taskService: TaskService, private router: Router) { }submit() {const id = this.route.snapshot.paramMap.get('id');if (id) {const existingTask = this.taskService.getTask(id);this.taskService.updateTask({...existingTask,...this.task});} else {this.taskService.addTask(this.task).subscribe(() => {this.router.navigate(['/']);});}}}
✔️ What You’ve Learned
In this chapter, you learned how to use HttpClient to add a task to the list. Since API communication is asynchronous, you learned to use the subscribe function to wait for the server’s response before navigating to the ”/” route.