Part IV - CRUD

In this part we will learn how to create, update and delete a user.

1 - User Setup

Firstly we will create the UserList component:

ng generate component user/component/user-list

Add this new component to app-routing.module.ts:

Listing 22 app-routing.module.ts
 1import { NgModule } from '@angular/core';
 2import { Routes, RouterModule } from '@angular/router';
 3import { LoginComponent } from './login/login.component';
 4import { DroneListComponent } from './drone/components/drone-list/drone-list.component';
 5import { UserListComponent } from './user/component/user-list/user-list.component';
 6
 7const routes: Routes = [
 8    { path: '', component: LoginComponent },
 9    { path: 'drones', component: DroneListComponent },
10    { path: 'users', component: UserListComponent },
11];
12
13@NgModule({
14    imports: [RouterModule.forRoot(routes)],
15    exports: [RouterModule]
16})
17export class AppRoutingModule { }

Secondly we will create the User service:

ng generate service user/services/user

And thirdly we will add the models folder and the actual models:

Listing 23 organization.ts
1export class Organization {
2    id?: string;
3    name = '';
4    description = '';
5}

This model represents the entity that is responsible for the users like: Beyond-vision, Enterprise-X and so on.

Listing 24 role.ts
 1import { Organization } from "./organization";
 2
 3export class Role {
 4    id: string;
 5    name: string;
 6    organization: Organization;
 7    constructor() {
 8        this.id = '';
 9        this.name = '';
10        this.organization = new Organization();
11    }
12}

This model is used to the access control on features of our application, for instance the role drone-pilot is allowed to list drones but is forbidden from deleting them, only the organization admin role is able to delete them.

Final model, user.ts:

Listing 25 user.ts
 1import { Organization } from "./organization";
 2import { Role } from "./role";
 3
 4export class User {
 5    id: string;
 6    username: string;
 7    email: string;
 8    profileImage: string;
 9    password: string;
10    hash: string;
11    description: string;
12    createdDate: Date;
13    token: string;
14    roles: Role[];
15    organization: Organization;
16
17    constructor() {
18        this.id = '';
19        this.username = '';
20        this.email = '';
21        this.profileImage = '';
22        this.password = '';
23        this.hash = '';
24        this.description = '';
25        this.createdDate = new Date();
26        this.token = '';
27        this.roles = [];
28        this.organization = new Organization();
29    }
30}


2 - Features Implementation

1 - User services

Next we will add the services to list, create, edit and delete users:

Listing 26 user.service.ts
 1import { HttpClient, HttpParams } from '@angular/common/http';
 2import { Injectable } from '@angular/core';
 3import { Observable } from 'rxjs';
 4import { PaginatorDto } from 'src/app/lib/models/paginator.dto';
 5import { User } from '../models/user';
 6
 7@Injectable({
 8providedIn: 'root'
 9})
10export class UserService {
11
12    backendUserUrl = 'https://bexstream.beyond-vision.pt/api/v1/user';
13
14    constructor(private http: HttpClient) { }
15
16    public getAllUsers(paginator: PaginatorDto): Observable<User[]> {
17        const params = new HttpParams()
18            .set('filter', paginator.filter)
19            .set('limit', paginator.limit.toString())
20            .set('offset', paginator.offset.toString())
21            .set('sort', paginator.sort)
22            .set('order', paginator.order);
23
24        return this.http.get<User[]>(this.backendUserUrl, {params});
25    }
26
27    public register(user: User): Observable<User> {
28        return this.http.put<User>(this.backendUserUrl, user);
29    }
30
31    public update(user: User): Observable<User> {
32        return this.http.post<User>(`${this.backendUserUrl}/${user.id}`, user);
33    }
34
35    public delete(user: User): Observable<User> {
36        return this.http.delete<User>(`${this.backendUserUrl}/${user.id}`);
37    }
38}


2 - List users

Listing 27 user-list.component.ts
 1import { Component, OnInit } from '@angular/core';
 2import { PaginatorDto } from 'src/app/lib/models/paginator.dto';
 3import { UserService } from '../../services/user.service';
 4import { FormBuilder } from '@angular/forms';
 5import { User } from '../../models/user';
 6
 7
 8@Component({
 9    selector: 'app-user-list',
10    templateUrl: './user-list.component.html',
11    styleUrls: ['./user-list.component.less']
12})
13export class UserListComponent implements OnInit {
14
15    users: User[] = [];
16
17    paginator: PaginatorDto = new PaginatorDto();
18
19    constructor(private formBuilder: FormBuilder,
20    private userService: UserService) { }
21
22    ngOnInit(): void {
23        this.paginator.limit = 0;
24        this.listUsers();
25    }
26
27    private listUsers() {
28        this.userService
29            .getAllUsers(this.paginator)
30            .subscribe((users) => {
31                this.users = users;
32            })
33    }
34}


On user-list.component.html let’s add a table with the list of users:

Listing 28 user-list.component.html
 1<h3>Users List</h3>
 2<table border="1">
 3    <thead>
 4        <th>Name</th>
 5        <th>Description</th>
 6        <th>Role</th>
 7        <th>Actions</th>
 8    </thead>
 9    <tbody>
10        <tr *ngFor="let user of users">
11            <td>{{ user.username }}</td>
12            <td>{{ user.description }}</td>
13            <td>{{ user.roles[0].name }}</td>
14            <td>
15                <button (click)="editUser(user)">Edit</button>
16                <button (click)="deleteUser(user)">Delete</button>
17            </td>
18        </tr>
19    </tbody>
20</table>


3 - Edit users

To edit a user we will firstly select the user using the “edit” button on the actions column. Then we will fill a form with the existing user data and allow for its edition. Finally the user will be able to submit the changed data.

On user-list.component.ts add:

Listing 29 user-list.component.ts
 1import { Component, OnInit } from '@angular/core';
 2import { PaginatorDto } from 'src/app/lib/models/paginator.dto';
 3import { UserService } from '../../services/user.service';
 4import { FormBuilder } from '@angular/forms';
 5import { Role } from '../../models/role';
 6import { User } from '../../models/user';
 7import { RoleService } from '../../services/role.service';
 8
 9@Component({
10    selector: 'app-user-list',
11    templateUrl: './user-list.component.html',
12    styleUrls: ['./user-list.component.less']
13})
14export class UserListComponent implements OnInit {
15
16    users: User[] = [];
17
18    paginator: PaginatorDto = new PaginatorDto();
19
20    updateUserForm = this.formBuilder.group({
21        username: '',
22        description: '',
23        password: ''
24    });
25
26
27    editingUser: User = null;
28
29    constructor(private formBuilder: FormBuilder,
30                private userService: UserService) { }
31
32    ngOnInit(): void {
33        this.paginator.limit = 0;
34        this.listUsers();
35    }
36
37
38    private listUsers() {
39        this.userService
40            .getAllUsers(this.paginator)
41            .subscribe((users) => {
42                this.users = users;
43            });
44    }
45
46    editUser(user: User) {
47        this.editingUser = user;
48
49        this.updateUserForm.patchValue({
50            username: user.username,
51            description: user.description,
52        });
53    }
54
55    updateUser() {
56        const updateUserFormValues = this.updateUserForm.value;
57        this.editingUser.username = updateUserFormValues.username;
58        this.editingUser.description = updateUserFormValues.description;
59        this.editingUser.password = updateUserFormValues.password;
60
61        this.userService
62            .update(this.editingUser)
63            .subscribe((user) => {
64                alert(`${user.username} has benn successfully updated!`);
65                this.listUsers();
66            });
67    }
68}


On user-list.component.ts add the user edition form:

Listing 30 user-list.component.html
 1<h3>Users List</h3>
 2<table border="1">
 3    <thead>
 4        <th>Name</th>
 5        <th>Description</th>
 6        <th>Role</th>
 7        <th>Actions</th>
 8    </thead>
 9<tbody>
10    <tr *ngFor="let user of users">
11        <td>{{ user.username }}</td>
12        <td>{{ user.description }}</td>
13        <td>{{ user.roles[0].name }}</td>
14        <td>
15            <button (click)="editUser(user)">Edit</button>
16            <button (click)="deleteUser(user)">Delete</button>
17        </td>
18    </tr>
19</tbody>
20</table>
21
22<hr>
23<hr>
24
25<h3>Edit User</h3>
26<form [formGroup]="updateUserForm" (ngSubmit)="updateUser()">
27    <div>
28        <label for="username">
29            Username
30        </label>
31        <input id="username" type="text" formControlName="username">
32    </div>
33
34    <div>
35        <label for="description">
36            Description
37        </label>
38        <input id="description" type="text" formControlName="description">
39    </div>
40
41    <div>
42        <label for="password">
43            Password
44        </label>
45        <input id="password" type="password" formControlName="password">
46    </div>
47
48    <button class="button" type="submit">Update</button>
49
50</form>


4 - Delete users

On user-list.component.ts add the following:

Listing 31 user-list.component.ts
 1import { Component, OnInit } from '@angular/core';
 2import { PaginatorDto } from 'src/app/lib/models/paginator.dto';
 3import { UserService } from '../../services/user.service';
 4import { FormBuilder } from '@angular/forms';
 5import { Role } from '../../models/role';
 6import { User } from '../../models/user';
 7
 8@Component({
 9    selector: 'app-user-list',
10    templateUrl: './user-list.component.html',
11    styleUrls: ['./user-list.component.less']
12})
13export class UserListComponent implements OnInit {
14
15    users: User[] = [];
16
17    paginator: PaginatorDto = new PaginatorDto();
18
19    updateUserForm = this.formBuilder.group({
20        username: '',
21        description: '',
22        password: ''
23    });
24
25
26    editingUser: User = null;
27
28    constructor(private formBuilder: FormBuilder,
29                private userService: UserService) { }
30
31    ngOnInit(): void {
32        this.paginator.limit = 0;
33        this.listUsers();
34    }
35
36
37    private listUsers() {
38        this.userService
39            .getAllUsers(this.paginator)
40            .subscribe((users) => {
41
42                this.users = users;
43            });
44    }
45
46    editUser(user: User) {
47        this.editingUser = user;
48
49        this.updateUserForm.patchValue({
50        username: user.username,
51        description: user.description,
52        });
53    }
54
55    updateUser() {
56        const updateUserFormValues = this.updateUserForm.value;
57        this.editingUser.username = updateUserFormValues.username;
58        this.editingUser.description = updateUserFormValues.description;
59        this.editingUser.password = updateUserFormValues.password;
60
61        this.userService
62            .update(this.editingUser)
63            .subscribe((user) => {
64                alert(`${user.username} has benn successfully updated!`);
65                this.listUsers();
66            });
67    }
68
69    deleteUser(user: User) {
70        this.userService
71            .delete(user)
72            .subscribe(result => {
73                alert(`${user.username} has benn successfully deleted!`);
74            });
75    }
76}


5 – Creating a new user

To create a new user we need to add new functionality, because when we create a user it has to have a role. This relationship is mandatory só we need to get a role from the backend first and then use it on the new user that we want to create.

To achieve this we need to generate a Role service to get the roles and then just use one of the many, for simplicity sake.

ng generate service user/services/role

And add the following code:

Listing 32 role.service.ts
 1import { HttpClient, HttpParams } from '@angular/common/http';
 2import { Injectable } from '@angular/core';
 3import { Observable } from 'rxjs';
 4import { Role } from '../models/role';
 5
 6@Injectable({
 7    providedIn: 'root'
 8})
 9export class RoleService {
10
11    backendUrl = 'https://bexstream.beyond-vision.pt/api/v1';
12
13    getAllUrl = this.backendUrl + '/role/all/filtered';
14
15    constructor(private http: HttpClient) { }
16
17    public getAll(): Observable<Role[]> {
18        const params = new HttpParams()
19        .set('filter', '')
20        .set('limit', '0')
21        .set('offset', '')
22        .set('sort', '')
23        .set('order', '');
24
25        return this.http.get<Role[]>(this.getAllUrl, {params});
26    }
27}


Now let’s use it on the user-list.component.ts:

Listing 33 user-list.component.ts
  1import { Component, OnInit } from '@angular/core';
  2import { PaginatorDto } from 'src/app/lib/models/paginator.dto';
  3import { UserService } from '../../services/user.service';
  4import { FormBuilder } from '@angular/forms';
  5import { Role } from '../../models/role';
  6import { User } from '../../models/user';
  7import { RoleService } from '../../services/role.service';
  8
  9@Component({
 10    selector: 'app-user-list',
 11    templateUrl: './user-list.component.html',
 12    styleUrls: ['./user-list.component.less']
 13})
 14export class UserListComponent implements OnInit {
 15
 16    users: User[] = [];
 17    roles: Role[] = [];
 18    paginator: PaginatorDto = new PaginatorDto();
 19
 20    updateUserForm = this.formBuilder.group({
 21        username: '',
 22        description: '',
 23        password: ''
 24    });
 25
 26    createUserForm = this.formBuilder.group({
 27        username: '',
 28        description: '',
 29        password: '',
 30        email: ''
 31    });
 32
 33
 34    editingUser: User = null;
 35
 36    constructor(private formBuilder: FormBuilder,
 37                private userService: UserService,
 38                private roleService: RoleService) { }
 39
 40    ngOnInit(): void {
 41        this.paginator.limit = 0;
 42        this.listUsers();
 43        this.getAllRoles();
 44    }
 45
 46
 47    private listUsers() {
 48        this.userService
 49            .getAllUsers(this.paginator)
 50            .subscribe((users) => {
 51
 52                this.users = users;
 53            });
 54    }
 55
 56    private getAllRoles() {
 57        this.roleService
 58            .getAll()
 59            .subscribe((roles) => {
 60                this.roles = roles;
 61            });
 62    }
 63
 64    editUser(user: User) {
 65        this.editingUser = user;
 66
 67        this.updateUserForm.patchValue({
 68        username: user.username,
 69        description: user.description,
 70        });
 71    }
 72
 73    updateUser() {
 74        const updateUserFormValues = this.updateUserForm.value;
 75        this.editingUser.username = updateUserFormValues.username;
 76        this.editingUser.description = updateUserFormValues.description;
 77        this.editingUser.password = updateUserFormValues.password;
 78
 79        this.userService
 80            .update(this.editingUser)
 81            .subscribe((user) => {
 82                alert(`${user.username} has benn successfully updated!`);
 83                this.listUsers();
 84            });
 85    }
 86
 87    deleteUser(user: User) {
 88        this.userService
 89            .delete(user)
 90            .subscribe(result => {
 91                alert(`${user.username} has benn successfully deleted!`);
 92            });
 93    }
 94
 95    createUser() {
 96        const createUserFormValues = this.createUserForm.value;
 97
 98        const newUser = new User();
 99
100        newUser.username = createUserFormValues.username;
101        newUser.description = createUserFormValues.description;
102        newUser.hash = createUserFormValues.password;
103        newUser.email = createUserFormValues.email;
104        newUser.roles = [this.roles[0]];
105
106
107        this.userService
108            .register(newUser)
109            .subscribe((user) => {
110                this.listUsers();
111            });
112    }
113}


Add the user creation form to user-list.component.ts:

Listing 34 user-list.component.html
 1<h3>Users List</h3>
 2<table border="1">
 3    <thead>
 4        <th>Name</th>
 5        <th>Description</th>
 6        <th>Role</th>
 7        <th>Actions</th>
 8    </thead>
 9<tbody>
10    <tr *ngFor="let user of users">
11        <td>{{ user.username }}</td>
12        <td>{{ user.description }}</td>
13        <td>{{ user.roles[0].name }}</td>
14        <td>
15            <button (click)="editUser(user)">Edit</button>
16            <button (click)="deleteUser(user)">Delete</button>
17        </td>
18    </tr>
19</tbody>
20</table>
21
22<hr>
23<hr>
24
25<h3>Edit User</h3>
26<form [formGroup]="updateUserForm" (ngSubmit)="updateUser()">
27    <div>
28        <label for="username">
29            Username
30        </label>
31        <input id="username" type="text" formControlName="username">
32    </div>
33
34    <div>
35        <label for="description">
36            Description
37        </label>
38        <input id="description" type="text" formControlName="description">
39    </div>
40
41    <div>
42        <label for="password">
43            Password
44        </label>
45        <input id="password" type="password" formControlName="password">
46    </div>
47
48    <button class="button" type="submit">Update</button>
49
50</form>
51
52<hr>
53<hr>
54
55<h3>Create User</h3>
56<form [formGroup]="createUserForm" (ngSubmit)="createUser()">
57
58    <div>
59        <label for="username">
60            Username
61        </label>
62        <input id="username" type="text" formControlName="username">
63    </div>
64
65    <div>
66        <label for="description">
67            Description
68        </label>
69        <input id="description" type="text" formControlName="description">
70    </div>
71
72    <div>
73        <label for="email">
74            E-mail
75        </label>
76        <input id="e-mail" type="text" formControlName="email">
77    </div>
78
79    <div>
80        <label for="password">
81            Password
82        </label>
83        <input id="password" type="password" formControlName="password">
84    </div>
85
86    <button class="button" type="submit">Create</button>
87
88</form>

Now go to http://localhost:4200, log in and then go to http://localhost:4200/users and edit or create new users.

Congratulations,you’ve finished the first beXStream tutorial. Now you are capable of modifying users, and listing the drones inside the organization. Explore more APIs at https://docs.beyond-vision.pt/bexstream/APIs.html

../../_images/crud-users.webp