4. Observables & HTTPRequests
4. 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 in de startbestanden. Maak alvast een nieuw project aan en plaats de interfaces hierin.
Startbestanden
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 https://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 in subjects.ts een overzicht van alle categorieën in The Open Library, gebruik dit overzicht om onderstaand menu op te bouwen. Om alle hoofdcategorieën op te halen uit de subjects array, kan je de methode Object.keys gebruiken.
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 die 2 attributen heeft. Het eerste attribuut bevat het werk (boek) dat weergegeven moet worden (type WorkSearchResult) en het twee attribuut 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 (te vinden in de startbestanden) gebruikt als cover. Een afbeelding in de assets map kan gebruikt worden als volgt:
<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. Om deze lay-out te bouwen moet je waarschijnlijk zelf nog wat CSS moeten schrijven.
Oefening 3: Werken ophalen
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 van de data. Deze datatypes gebruiken namen in camelCase formaat, terwijl de API-data in snake_case teruggeeft.
Maak een nieuwe ApiService aan en 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) opnieuw nuttig zijn. Ook de delete operator kan nuttig zijn, deze kan gebruikt worden om attributen uit een object te verwijderen. Onderstaande code verwijdert de property met de naam attribuutNaam uit het object voorbeeld.
delete voorbeeld[attribuutNaam]API call uitvoeren
Onderstaande URL kan gebruikt worden om de eerste twee boeken in de categorie computer science op te halen.
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 overgeslagen 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.
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 en sommige bevatten een spatie. De API verwacht dat de categorie in lower case staat en dat alle spaties vervangen worden met underscores.
Gebruikt de nieuwe methode vervolgens 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 leidt 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 lestekst 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: FileReader | null = 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 opgehaald hebt bevat nog geen beschrijving voor een boek. Deze info kan opgehaald worden via de works api.
Via onderstaande URL worden de details voor het boek 'The Hobbit' opgehaald. 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 20 boeken per pagina. Telkens je naar onder scrolt, wordt de volgende pagina geladen.
Voeg tenslotte nog de optie toe om de beschrijving van een boek volledig te lezen via een alert.