Skip to content

Service and CRUD

The expected state of the application after the "Component development" section is completed: [get code]

In this part, we will create a new service that will be responsible for communication with a remote server and perform basic CRUD functions.

The command to create a new site is almost identical to the component generation command:

ng generate service <service-name> [options]
# Short version
ng g service <service-name> [options]

The list of available options can be found here.

Single student model

Before building a CRUD website, let's define a single student interface to work with data. Let's create a new student.ts file inside thesrc / app folder and add the following code to it:

export interface Student {
  id: number;
  name: string;
  email: string;
}

We will be able to use the interface added in this way similarly to basic data types. Word export before the interface means that it can be exported and imported in the appropriate application files.

Website creation

Let's start by creating a website containing an initial list of students we want to manage. The website will be useful for data manipulation. The components should not download or write data directly, but should focus on the presentation of the data and regulate access to it among different classes. So let's create the site using the command-line interface by typing:

ng generate service Student

The command will generate the skeleton of the class StudentService in src/app/student.service.ts as follows:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class StudentService {

  constructor() { }

}

CRUD functionality

To run the Create-Read-Update-Delete functionality, we will have to modify three files:

  • src/app/student.service.ts
  • src/app/students/students.component.ts
  • src/app/students/students.component.html

Enabling the HTTP mechanism

To be able to communicate with remote servers via the HTTP protocol, we need an angular mechanism calledHttpClient. Let's make it available anywhere in the application in two steps. First, let's add it to the main src/app/app.module.ts module by importing it at the very top of the file:

import { HttpClientModule } from '@angular/common/http';

Then, still in the same file, add HttpClient to the imports array:

imports: [
  BrowserModule,
  HttpClientModule
],

Preparing the website for CRUD

Let's modify the student.service.ts site to be able to manage the student list. To generate the list itself we will use the [JSONPlaceholder] platform (https://jsonplaceholder.typicode.com), which offers various types of * pretend * REST API.

Let's add the mechanisms HttpClient andHttpHeaders (used to configure the header for the HTTP request) by importing them in service file:

import { HttpClient, HttpHeaders } from '@angular/common/http';

Due to the fact that we will be connecting to a remote server, StudentService has to wait for a response from the server, so the CRUD methods that we will define soon must be executed asynchronously (asynchronous functions do not block further code execution). So you need to import the class Observable, which is a key component of the RxJS library.

import { Observable } from 'rxjs';

Let's also import the previously created Student interface:

import { Student } from './student';

While still in StudentService, let's inject HttpClient into the constructor in a private property called http:

constructor(private http: HttpClient) { }

Now let's define (before the constructor) a private variable studentsUrl with the address to the user resource:

private studentsUrl = 'https://jsonplaceholder.typicode.com/users';

READ: Read student data

To read data from the API, we need to use the http.get() method from the HttpClient class inside the website we created. This method will return an object of the form Observable <Student[]>, which will print an array of students obtained during the HTTP request.

getStudents(): Observable<Student[]> {
  return this.http.get<Student[]>(this.studentsUrl);
}

The server data API determines the shape of the JSON data that our application will receive. In contrast, our data API returns student data as tables.

It may also happen that we do not want to download a list of all students, but only a specific student with a given ID number. So let's add another method that will make it possible:

getStudent(id: number): Observable<Student> {
  const url = `${this.studentsUrl}/${id}`;
  return this.http.get<Student>(url);
}

Note three important differences from the getStudents() method:

  • getStudent() creates a request url with the id of the requested student.
  • The server should respond with one student, not a series of students.
  • getStudent() returns Observable <Student> * (the observable "Student" object) * instead of the observable array of students.

UPDATE: Updating student data

The general structure of the updateStudent() method is similar to the getStudents() structure, but it uses http.put() to persist the student's changes to the server. As we are using the fake REST API in this project, these changes will not be saved.

First, let's add a new object under the studentsUrl variable, i.e.httpOptions. The web API expects a special header in data update requests.

httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

Now we can start creating a new method:

updateStudent(student: Student): Observable<Student> {
  const url = `${this.studentsUrl}/${student.id}`;
  return this.http.put<Student>(url, student, this.httpOptions);
}

The HttpClient.put() method takes three parameters:

  • URL
  • Data to be updated (in this case, the edited student)
  • Options for the sent request

CREATE: Create a new student

As with the upgrade, we will not create a new user on the * JSONPlaceholder * server, but we will simulate this event.

addStudent(student: Student): Observable<Student> {
  return this.http.post<Student>(this.studentsUrl, student, this.httpOptions);
}

The addStudent() method differs from updateStudent() in two ways:

  • Calls HttpClient.post() instead of put().
  • Expects the server to generate an id (as well as all the rest of the object) for a new student it returns asObservable <Student>.

DELETE: Deleting a student

deleteStudent(student: Student): Observable<Student> {
  const url = `${this.studentsUrl}/${student.id}`;
  return this.http.delete<Student>(url, this.httpOptions);
}

Note the following:

  • The method calls HttpClient.delete().
  • The url is the url with the student id to be removed.
  • Unlike put() and post(), no data is sent.