========================= Part III - Listing Drones ========================= In this part we will explain how to get an array of data from the bexstream backend API. In this case we will show how to list all the drones. Firstly we will create a new folder called drone and inside the “drone” folder we will add the components, services and models related to drones. 1 - Drone Setup ==================== Let’s create the DroneListComponent: ``ng generate component drone/components/drone-list`` Create the AssetService: ``ng generate service drone/services/asset`` Add the “models” folder inside the “drone” folder. This models folder will be used for the component specific models like the following two files: .. highlight:: ts .. code-block:: :linenos: :caption: drone.ts export class Drone { id: string; latitude: number; // last latitude recorded once disconnects longitude: number; // last longitude recorded once disconnects onMission: boolean; hasCamera?: boolean; has360Camera?: boolean; hasSpeaker?: boolean; isDirectConnect?: boolean; // usually via telemetry constructor() { this.id = ''; this.latitude = 0.0; this.isDirectConnect = false; this.longitude = 0.0; this.onMission = false; this.hasSpeaker = false; this.hasCamera = false; this.has360Camera = false; } } .. code-block:: :linenos: :caption: asset.ts import { Drone } from "./drone"; export class Asset { id: string; name: string; mountPoint: number | null; isActive: boolean; drone?: Drone; lastConnected: Date | null; isDirectConnect?: boolean; // usually via telemetry missionCount?: number | null; constructor(type: string) { if (type === 'Drone') { this.drone = new Drone(); } this.id = ''; this.name = ''; this.mountPoint = null; this.isActive = false; this.lastConnected = null; } } | To wrap the models part up we need to create the “PaginatorDTO” model. Inside the lib folder create the “models” folder and add the paginator.dto.ts file with the following code: .. code-block:: :linenos: :caption: paginator.dto.ts export class PaginatorDto { filter: string; limit: number; offset: number; sort: string; order: string; pageSizes: number[]; subFilter: string; constructor(filter?: string, limit?: number, offset?: number, sort?: string, order?: string, pageSizes?: number[], subFilter?: string) { if (filter !== undefined) { this.filter = filter; } else { this.filter = ''; } if (limit !== undefined) { this.limit = limit; } else { this.limit = 5; } if (offset !== undefined) { this.offset = offset; } else { this.offset = 0; } if (sort !== undefined) { this.sort = sort; } else { this.sort = 'createdDate'; } if (order !== undefined) { this.order = order; } else { this.order = 'ASC'; } if (pageSizes !== undefined) { this.pageSizes = pageSizes; } else { this.pageSizes = [5, 10, 15]; } if (subFilter !== undefined) { this.subFilter = subFilter; } else { this.subFilter = ''; } } } The PaginatorDto is used in every data retrieval service like the following. The paginator has the purpose of reducing the quantity of data to be retrieved. To know more check the bexstream api swagger. | 2 - Features implementation =========================== Now that we have created the models, let’s implement the code to get them from the server. On asset.service.ts add the following code: .. code-block:: :linenos: :caption: asset.service.ts import { HttpClient, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/internal/Observable'; import { PaginatorDto } from 'src/app/lib/models/paginator.dto'; import { Asset } from '../models/asset'; @Injectable({ providedIn: 'root' }) export class AssetService { backendUrl = 'https://bexstream-preprod.beyond-vision.com/api/v1/asset'; getAllDronesUrl = this.backendUrl + '/all/drone'; constructor(private http: HttpClient) {} public getAllDrones(paginator: PaginatorDto): Observable { const params = new HttpParams() .set('filter', paginator.filter) .set('limit', paginator.limit.toString()) .set('offset', paginator.offset.toString()) .set('sort', paginator.sort) .set('order', paginator.order); return this.http.get(this.getAllDronesUrl, {params}); } } | Now we need to use this service on the DroneListComponent to get the drones. On drone-list.component.ts add the following code. .. code-block:: :linenos: :caption: drone-list.component.ts import { Component, OnInit } from '@angular/core'; import { Asset } from '../../models/asset'; import { AssetService } from '../../services/asset.service'; @Component({ selector: 'app-drone-list', templateUrl: './drone-list.component.html', styleUrls: ['./drone-list.component.less'] }) export class DroneListComponent implements OnInit { assets: Asset[] = []; paginator: PaginatorDto = new PaginatorDto(); constructor(private assetService: AssetService) { } ngOnInit(): void { this.listDrones(); } private listDrones() { this.assetService .getAllDrones(this.paginator) .subscribe((assets) => { this.assets = assets; }); } } | 3 - Visualization ================= Third step is to show the drone on the UI. To perform this we will add the following code to drone-list.component.html: .. code-block:: html+ng2 :linenos: :caption: drone-list.component.html

Drones List



{{ asset.name }}

{{ asset.drone.id }}

Latitude: {{ asset.drone.latitude }}, Longitude: {{ asset.drone.longitude }}

On Mission

Not on Mission

Last Connected: {{asset.lastConnected}}


| 4 - Using new component ======================= Now that we have the drone list done we need to add the route to it on app-routing.module.ts: .. code-block:: :linenos: :caption: app-routing.module.ts :emphasize-lines: 4, 8 import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { LoginComponent } from './login/login.component'; import { DroneListComponent } from './drone/components/drone-list/drone-list.component'; const routes: Routes = [ { path: '', component: LoginComponent }, { path: 'drones', component: DroneListComponent }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } | 5 - App Routing =============== To complete this part we just need to add a routing feature to improve usability. After we log in we want out app to change to the drones list. To do this, after we log in successfully, we need to route the user to the drone list component. We achieve that by doing the following: .. code-block:: :linenos: :caption: login.component.ts :emphasize-lines: 4, 47 import { Component, OnInit } from '@angular/core'; import { FormBuilder } from '@angular/forms'; import { HttpClient } from '@angular/common/http'; import { Router} from '@angular/router'; import { User } from './models/user'; import { WebStorageService } from '../lib/web-storage.service'; @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.less'] }) export class LoginComponent implements OnInit { user: User = new User(); loginForm = this.formBuilder.group({ username: '', password: '' }); private readonly defaultURLRoute = 'drones'; constructor(private formBuilder: FormBuilder, private http: HttpClient, private webStorage: WebStorageService, private router: Router) { } ngOnInit(): void { } /** * User authentication */ public authenticate(): void { const loginFormValues = this.loginForm.value this.user.username = loginFormValues.username; this.user.password = loginFormValues.password; this.http.post('https://bexstream-preprod.beyond-vision.com/api/v1/auth/user', this.user) .subscribe((result) => { if (result.user) { alert(`${result.user.username} has benn successfully logged in!`); this.webStorage.storageToken(result.token); this.router.navigate([this.defaultURLRoute]); } else { alert(`Error on login. Please check the username and the password!.`); } }); } } | | Now run your app: ``ng serve`` If Part III was finished successfully, after you login, you should be able to see the list of drones that are inside the *tutorial* organization. .. image:: ../../_static/images/bexstream/tutorial/drone-list.webp :align: center