Lab 12 - Error Handling and Slow Connections
Intro
In this lab we will ensure a good user experience by making it clear when the application is getting data, and handling the case where the server doesn't respond
1. Create a spinner
- Create a component to display a spinner on screen
ng g c spinner
- Set the HTML for this component to:
<svg width="48" height="48" viewBox="0 0 48 48" aria-label="Loading..." role="img">
<circle
cx="24"
cy="24"
r="20"
fill="none"
stroke="#1976d2"
stroke-width="4"
stroke-linecap="round"
stroke-dasharray="100"
stroke-dashoffset="60"
>
<animateTransform
attributeName="transform"
type="rotate"
from="0 24 24"
to="360 24 24"
dur="1s"
repeatCount="indefinite"
/>
</circle>
</svg>
2. Display a spinner while data is loading
-
In the who-is-in-the-building component, set a class level variable called isLoading with a default value of false.
-
When we call the getData method, set the value of isLoading to true.
-
When we set the accessLogs data, set the value of isLoading to false.
Click here to see the sample solution
import { Component, OnInit, signal } from '@angular/core';
import { RestService } from '../rest.service';
import { AccessRecord } from '../data/AccessRecord';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-who-is-in-the-building',
standalone: true,
imports: [],
templateUrl: './who-is-in-the-building.component.html',
styleUrl: './who-is-in-the-building.component.css'
})
export class WhoIsInTheBuildingComponent implements OnInit {
selectedBuilding = "";
isLoading = false;
accessLogs = signal<AccessRecord[]>([]);
private restService = inject(RestService);
private route = inject(ActivatedRoute);
ngOnInit(): void {
this.route.params.subscribe(params => {
this.selectedBuilding = params['building'] || "";
if (this.selectedBuilding !== "") this.getData();
});
}
getData() {
this.isLoading = true;
this.restService.getAccessLogs(new Date()).subscribe(data => {
const buildingRecords = data.filter(record => record.building.name === this.selectedBuilding );
const lastRecordsMap = new Map<number, AccessRecord>();
buildingRecords.forEach(record => {
lastRecordsMap.set(record.user.id, record);
});
const lastRecords = Array.from(lastRecordsMap.values());
const insideRecords = lastRecords.filter(record => record.status === true);
this.accessLogs.set(insideRecords);
this.isLoading = false;
});
}
}
-
Place the spinner component near the top of HTML of the component.
-
Test the application in your browser. You might want to set the netwrok throttling to slow 4G to see the spinner in action.
2. Handle server errors
-
In the rest service, temporarily change the Building URL to the wrong end point ('http://localhost:8080/api/buildings')
-
Amend the subscription in the emergency page component to the building observable to handle server errors - display a suitable message on the screen if an error occurs.
Click here to see the sample solution
errorMessage = "";
ngOnInit(): void {
this.restService.getBuildings().subscribe(
{
next: data => {
this.buildings.set(data);
},
error: error => {
this.errorMessage = `Failed to load buildings data. ${error.message}`;
console.log(error);
}
}
)};
- Test the changes in your browser.
3. Improve the user experience
Implement the spinner for the loading of the list of buildings. If an error occurs, don't show the who-is-in-the-building component.
In the who-is-in-the-building component, don't show any data if there is no selected building