Les 2: Ionic & Angular

Sebastiaan HenauOngeveer 5 minuten

Les 2: Ionic & Angular

In deze verdiepende oefening bouw je een applicatie waarmee een gebruiker voor zijn favoriete TV shows kan bijhouden hoeveel aflevering hij bekeken heeft. Welke afleveringen hij nog niet bekeken heeft, hoeveel tijd hij gespendeerd heeft aan TV shows, ...

Doorheen de lessenreeks worden deze oefeningen steeds uitgebreid met nieuwe leerstof. Op het einde van de lessenreeks bevat dit project dus alle leerstof.

Dit zijn uitdagende oefeningen die bedoelt zijn als uitbreiding voor diegenen die de basis oefeningen sneller af hebben. Het niveau van deze oefeningenreeks ligt hoger dan dat van de basis oefeningen en deze oefeningen zijn minder gedetailleerd uitgeschreven. Dit betekent wel dat deze oefeningen een zeer goede voorbereiding zijn op je project. Als je deze reeks afgewerkt krijgt heb je een app gebouwd die groter en complexer is dan wat er van jou gevraagd wordt voor je project.

Deze oefeningen zijn optioneel en moeten niet verplicht gemaakt worden. Dit zijn grote oefeningen, het is mogelijk dat er nog fouten staan in de opgave of dat hier en daar iets vergeten is. Kom je zo'n fout tegen, gelieve dit door te geven via de issue trackeropen in new window.

Deze les bouw je drie views, ondersteund door een aantal klassen en interfaces.

Figuur 1: Eindresultaat

Structuur

Maak een nieuw project aan en kies voor een tabs lay-out. De componentenboom van de app ziet er momenteel als volgt uit

Figuur 1: Huidige App Structuur

Pas deze structuur aan zodat alle ExploreContainer elementen (en de bijhorende map) verwijderd worden uit het project.

Pas vervolgens de titels van de tabbladen aan. Voor het eerste tabblad is de titel “Series”, voor het tweede tabblad “Movies” en voor het derde tabblad “Lists”.

Bekijk de code in tabs.page.html en pas de icoontjes van de tabbladen aan. Voor het eerste tabblad gebruiken we het “tv” icoon, voor het tweede tab het “videocam” icoon en voor het derde tab het “list” icoon. Later voegen we nog een vierde tabblad toe, hierin tonen we statistieken over het kijkgedrag van de gebruiker. Voeg al een knop toe met het “stats-chart” icoon en zorg ervoor dat deze knop voorlopig nog naar tabblad 3 verwijst. Je App ziet er nu als volgt uit.

Figuur 2: Tussenresultaat 1

Een app zonder menu knoppen kan natuurlijk niet gebruikt worden. We voegen een "search" en "add" knop toe aan de menubalk van het eerste tabblad. Voorlopig doen deze knoppen nog niets.

Figuur 3: Tussenresultaat 2

Dummy data en types

Voor je de views kan beginnen te bouwen heb je data nodig, de dummy data exporteert een array dummySeriesData van Series objecten.

Deze data komt van https://imdb-api.com/open in new window, in verdere oefeningen spreek je deze API zelf aan en zorg je voor persistente dataopslag. Voorlopig werk je met dummy data en verdwijnen alle wijzigingen nadat je de applicatie herlaad.

In deze dummy data wordt gebruik gemaakt van twee datatypes, Series en Episode. De meeste attributen zijn rechtstreeks overgenomen uit het resultaat van de API. Daarnaast zijn er in deze datatypes ook enkele attributen aanwezig die niet uit de API afkomstig zijn.

Maak onderstaande types aan in /src/datatypes. Voorzie voor elk datatype zowel een interface als een klasse die deze interface gebruikt in een copy constructoropen in new window.

Let op: de opgesomde methodes en velden zijn niet exhaustief, je zult zelf nog een aantal methodes en/of instantievariabelen moeten toevoegen.

Datatype 1: Episode

Dit object stelt een aflevering voor in een serie en bevat volgende attributen.

  • title: De titel van de aflevering.
  • watchCount: Het aantal keer dat de aflevering bekeken is, dit attribuut komt niet uit de API en wordt in de klasse geĂŻnitialiseerd op 00, het moet echter ook mogelijk zijn om via de copy constructor een waarde mee te geven.
  • image: De URL van een afbeelding, meestal een screenshot uit de aflevering.
  • released: De datum waarop de aflevering uitgebracht is, de datum wordt als string bewaard.
  • plot: Een beschrijving van het plot van de aflevering.
  • imDbRating: De score die de aflevering op IMDB gekregen heeft, wordt bewaard als string.
  • runtime: De gemiddelde runtime van een aflevering.

De klasse Episode bevat getters voor de verschillende attributen. Daarnaast zijn ook onderstaande methodes nodig.

  • incrementWatched: Zoals de naam doet vermoeden verhoogt deze methode het aantal keer dat de aflevering bekeken is.
  • decrementWatched: Verminder het aantal keer dat de aflevering bekeken is, hou er rekening mee dat een aflevering geen negatief aantal keer bekeken kan zijn.
  • hasBeenWatched: Geeft true terug als de aflevering bekeken is, false als dit niet het geval is.
  • getReleaseDateAsDateObjects: Een methode die de datum uit de API converteert naar een JavaScript date object.

Hint

Om de conversie te maken van de string voorstelling van de datum die van de API komt naar een JS Date object installeer je best een andere tool gebruiken omdat vanilla JS geen goede data parser heeft.

Er zijn een hele hoop opties, je bent vrij om te kiezen, maar data-fns wordt aangeraden. Je kan dit pakket eenvoudig via pnpm installeren

pnpm add date-fns

Vervolgens moet je het pakket importeren in je TypeScript bestand via

import {parse} from 'date-fns';

Om de conversie te maken kan je vervolgens volgende lijn code gebruiken.

const resultAsJSDate = parse(releasedFromAPI, "d MMM. yyyy", new Date());

Datatype 2: Series

Dit datatype stelt een volledige TV serie voor en bevat volgende instantie variabelen.

  • seasons: Een 2-dimensionale array van Episode objecten. De eerste index geeft het seizoen weer, de tweede de aflevering in dat seizoen.
  • name: De naam van de serie.
  • image: De URL van de poster van de serie.
  • imDbId: Het IMDB-id van de serie, IMDB gebruikt string id's.
  • plot: De beschrijving van de serie.

Naast deze attributen heeft de klasse Series de nodige getters, maar ook onderstaande methoden.

  • getNumberOfUnwatchedEpisodes: Een methode die het aantal nog niet bekeken afleveringen telt en dit terug geeft.
  • getNextUnwatchedSeasonNumber: Een methode die het eerstvolgende seizoen met niet bekeken afleveringen bepaald en dit teruggeeft.
  • getNextUnwatchedEpisodeNumber: Een methode die het volgnummer van de eerste nog niet bekeken aflevering bepaald en dit teruggeeft.
  • getNextEpisodeAsString: Een methode die de eerstvolgende nog niet bekeken aflevering teruggeeft als een string van de vorm 'SXE', waar S vervangen wordt met het volgnummer van het seizoen dat de eerstvolgende niet bekeken aflevering bevat, en waar E vervangen wordt met het volgnummer van de eerstvolgende nog niet bekeken aflevering binnen dat seizoen.
  • getNumberOfEpisodes: Bepaalt het totaal aantal afleveringen in de serie.
  • getNextEpisodeReleaseDate: Haal de releasedatum van de eerste niet bekeken aflevering op.
  • incrementWatched: Markeer de eerstvolgende nog niet bekeken aflevering als bekeken.
  • getNumberOfSeasons: Bepaal het totaal aantal seizoenen in de serie en geef dit terug.
  • hasFutureAirDate: Controleert of de serie een aflevering heeft die nog niet uitgezonden is en waarvan de uitzenddatum bekend is (in het geval de release datum nog niet bekend is, geeft de API een lege string terug, de uitzenddatum moet natuurlijk ook na de huidige dag liggen).

Datatype 3: WatchHistory

Dit object stelt een bekeken aflevering voor. Elke keer een aflevering als bekeken gemarkeerd wordt zal een nieuw WatchHistory object aangemaakt moeten worden.

Deze interface bevat volgende instantievariabelen.

  • season: Het seizoen van de bekeken aflevering;
  • episode: Het nummer van de bekeken aflevering;
  • imDbId: Het id van de serie waartoe de aflevering behoord.
  • watchDate: De datum waarop de aflevering bekeken is (als timestamp sinds epoch).

UI Structuur

Bekijk de documentatie voor <ion-segment>open in new window en gebruik de informatie die je hier vindt om bovenaan je applicatie, in het “Series” tab drie knoppen toe te voegen. Namelijk "Series", "Next" en "Recent". De knoppen moeten zowel op kleine als grote schermen bruikbaar zijn.

De verschillende segmenten moeten uit je TypeScript file komen, je mag deze dus niet hardcoderen in de template.

Zorg er voor dat de segment knoppen gebruikt kunnen worden om de view aan te passen. Bouw met behulp van het *ngIf directive onderstaande lay-out na. De klasse 'ion-padding-top' is toegevoegd aan de content van elk segment bevat.

Figuur 4: UI Structuur

Series

Maak gebruik van een <ion-list> en bouw onderstaand UI na. Gebruik de methodes die je aangemaakt hebt in de klasse Serie.

Figuur 5: Series (Deel 1)

Om de covers op dezelfde manier weer te geven als in het screenshot kan je onderstaande CSS code toevoegen aan je project.

.cover {
    width: 20vw;
    margin: .5em 0;
}

Next Series

Het "Next" tabblad toont de afleveringen die nog niet uitgezonden zijn, maar voor welke er wel een uitzenddatum bekend is. De afleveringen worden oplopend op uitzenddatum gesorteerd. Je kan het UI van het vorige tabblad bijna volledig overnemen.

Afhankelijk van wanneer je deze oefening maakt kunnen de afleveringen die getoond worden verschillen, deze zijn tenslotte gebaseerd op de huidige datum.

Op lijn 163 van de dummy data kan je een aflevering vinden die altijd morgen uitgezonden wordt.

Figuur 6: Series (Deel 2)

Watch History

Telkens er een aflevering bekeken wordt, verschijnt deze ook in het laatste tabblad. Dit tabblad toont een de laatst bekeken afleveringen in aflopende volgorde.

Slechts een bepaald aantal van de laatst bekeken afleveringen wordt behouden, niet de volledige geschiedenis. Hoeveel dit er zijn wordt later door de gebruiker bepaald, voorlopig hardcodeer je de limiet op 10.

Figuur 7: Watch history
Laatst geĂĽpdate:
Bijdragers: Sebastiaan Henau