Les 5: Observables & HTTPRequests
Les 5: Observables & HTTPRequests
Tijdens deze oefeningenreeks bouw je een applicatie waarmee door de collectie van The Open Library gebladerd kan worden.
Voor deze opgave worden enkele interfaces voorzien. Maak alvast een nieuw project aan en plaats de interfaces hierin.
Oefening 1: Categorieën
The Open Library voorziet de mogelijkheid om boeken op te halen op basis van de categorie waartoe ze behoren, meer informatie over deze mogelijkheid is te vinden op openlibrary.org/dev/docs/api/subjects.
Voordat de boeken opgehaald kunnen worden, moet er natuurlijk de mogelijkheid zijn om een bepaalde categorie te selecteren. In de startbestanden, vind je de file subjects.ts. Gebruik deze file om onderstaand menu op te bouwen.
Oefening 2: Boeken per categorie - loading
Maak een nieuwe pagina WorksPage, deze pagina krijgt de categorie waarvoor de boeken getoond moeten worden als navigatieparameter.
De pagina toont de boeken aan de hand van een nieuwe component WorkComponent. Deze component heeft 2 attributen, het werk (boek) dat weergegeven moet worden (type WorkSearchResult) en een boolean die aangeeft of de data aan het laden is of niet.
Voorlopig wordt deze component enkele keren getoond met het attribuut loading op true. Er wordt nog geen data opgehaald. In onderstaande gif is de afbeelding placeholder.png gebruikt als cover, je vindt deze in de startbestanden. Een afbeelding kan in de map assets geplaatst worden en vervolgens gebruikt worden als:
<img src='/assets/placeholder.png'>
Bekijk onderstaande video en probeer een gelijkaardige lay-out (moet niet 100% gelijk zijn) te bouwen aan de hand van een <ion-card>. De loading animation zijn gemaakt via de <ion-skeleton-text> component. Je zult om deze lay-out te bouwen waarschijnlijk zelf nog wat CSS moeten schrijven.
Oefening 3: Werken ophalen
Om boeken op te halen kan een URL als
gebruikt worden. Merk op dat er geen API keys nodig zijn, de API is volledig open.
Deze URL bestaat uit 3 variabele delen, die hierboven telkens in het vet aangeduid zijn:
- Het onderwerp (categorie) waarvoor boeken opgehaald moeten worden.
- Optionele pagination info:
- De parameter limit geeft weer hoeveel resultaten er teruggegeven moeten worden, in dit geval zijn dat er dus 2.
- De parameter offset geeft weer hoeveel resultaten er overgeslaan moeten worden, voordat de limit begint te tellen. In dit geval wordt 0 gebruikt, wat betekent dat we de eerste pagina bekijken. Zou je hier 2 gebruiken, dan krijgen we resultaten 3-4 terug, de tweede pagina dus.
Voorbereiding
Er zijn al datatypes aanwezig in de startbestanden waarmee het resultaat van een oproep naar het /subjects endpoint gerepresenteerd kan worden. Het root datatype voor dit soort oproepen is SubjectSearchResult. Bekijk het resultaat van bovenstaande URL en/of de datatypes, zodat je een idee krijgt van de structuur. Deze datatypes gebruiken namen in camelCase formaat, terwijl de API-data in snake_case teruggeeft.
Maak een nieuwe service aan, waarin je de API calls zult toevoegen. Schrijf in deze service eerst een methode die gebruikt kan worden om alle attributen van een object die in snake_case staan om te vormen naar camelCase.
Hiervoor kan de methode Object.keys(object: any) nuttig zijn. Deze geeft een array van alle attributen in het object terug. Ook de delete operator kan nuttig zijn, deze kan gebruikt worden om attributen uit een object te verwijderen:
delete voorbeeld[attribuutNaam]
verwijderd de sleutel met naam attribuutNaam uit het object voorbeeld.
API call uitvoeren
Schrijf een methode waarmee alle werken voor een bepaalde categorie opgehaald kunnen worden. Deze methode moet pagination ondersteunen en geeft een promise van het type SubjectSearchResult terug. Gebruikt de RxJS pipe methode en de methode die je hierboven geschreven hebt, om het object dat je binnenkrijgt te converteren naar een element van het type SubjectSearchResult. Gebruik voorlopig een kleine paginagrootte, als laatste oefening, voeg je pagination toe.
De categorieën die je gebruikt heb in de eerste opgave beginnen met een hoofdletter. Wil je deze gebruiken om de boeken in de categorie op te halen, dan zul je deze eerst moeten omzetten naar lower case. Sommige categorieën bevatten ook een spatie, deze moet geconverteerd worden naar een underscore ("_") voor je de API-call uitvoert.
Gebruikt deze nieuwe methode nu om een aantal boeken op te halen en de titel en auteurs te tonen, de beschrijving en cover blijven voorlopig leeg. Gebruikt hier opnieuw de WorkComponent voor. Initieel wordt de loading-versie van de component getoond, maar zodra de data opgehaald is, wordt dit vervangen met effectieve data.
Oefening 4: Covers
De covers van de boeken zijn heel eenvoudig op te halen, elk werk heeft een attribuut coverEditionKey, dit attribuut kan gebruikt worden om een URL van de vorm
Hier is het vetgedrukte deel, de waarde van het coverEditionKey attribuut. Je kan nu eenvoudig het src attribuut van de afbeelding instellen. Dit leid tot onderstaand resultaat.
De afbeeldingen worden in stukjes geladen. Het is voor een gebruiker aangenamer, als de afbeelding eerst op de achtergrond geladen wordt en dan, als de afbeelding volledig geladen is, getoond wordt.
De tweede afbeelding is een wit kader, hier is niets aan te doen, dit is een probleem in de API.
Schrijf, om dit probleem op te lossen, een methode downloadCover in de ApiService. Deze methode geeft een Promise<Blob> terug. Hoe je dit doet, kan je in de les-tekst vinden.
Het resultaat van deze methode kan je als volgt verwerken.
export class WorkComponent implements OnInit {
// Niet relevante code weggelaten.
cover = '/assets/placeholder.png';
reader = new FileReader();
#downloadImage(url: string): void {
this.reader.addEventListener('loadend', () => {
this.cover = this.reader.result as string;
this.reader = null;
});
this.apiService.downloadCover(url).then(x => this.reader.readAsDataURL(x));
}
}
Nu blijft de placeholder zichtbaar tot de afbeelding in memory geladen is, daarna wordt het src attribuut vervangen met een dataURL.
Oefening 5: Description ophalen
De data die je in oefening 3 hebt opgehaald bevat nog geen beschrijving voor een boek. Deze info kan opgehaald worden via de works api.
Via de URL
kunnen de details van het boek 'The Hobbit', opgehaald worden. Het laatste deel van deze URL, /works/OL262758W, is beschikbaar onder de naam key in de SubjectSearchResult objecten.
Schrijf een methode die de details van een werk ophaalt en dit teruggeeft als een Promise<Work>. Als je het datatype Work bekijkt, zie je dat het attribuut description op verschillende manieren teruggegeven kan worden door de API. Gebruik de pipe methode van RxJS om ervoor te zorgen dat de description steeds als string bewaard wordt. Als de API geen beschrijving teruggeeft, gebruikt je de tekst "No description available".
Je zult merken dat de beschrijvingen voor bepaalde boeken heel lang zijn. Je kan volgende CSS-code gebruiken om de lay-out wat te fatsoeneren.
.description {
margin-bottom: 2em;
max-height: 15vh;
width: 70vw;
margin-right: 2em;
overflow: scroll;
}
Oefening 6: Finishing touches
Gebruik de <ion-infinite-scroll> component om pagina's te creëren met een 20-tal boeken per pagina. Telkens je naar onder scrolt, wordt de volgende pagina geladen.
Voeg ook nog de optie toe om de beschrijving van een boek volledig te lezen via een alert.