HTKA0120 Frontend-sovelluskehitys

1 Opintojakson perustiedot
2 Ohjelmointiympäristö
3 Frontend-sovellus
3.1 SPA-sovellus
3.2 Asynkroniset pyynnöt
4 Angular
4.1 Angular-sovelluksen luonti, julkaisu ja debuggaus
4.1.1 Sovelluksen luonti
4.1.2 Sovelluksen julkaisu
4.1.3 Sovelluksen debuggaus
4.2 Angular-sovelluksen rakenneosat ja toimintaperiaate
4.2.1 Rakenneosat
4.2.2 Toimintaperiaate
4.2.3 Esimerkkejä
4.3 Frontend-sovelluksen peruspiirteet Angularissa
4.3.1 Reititys
4.3.2 Data Binding
4.3.3 Dependency Injection
4.3.4 Komponenttien välinen kommunikaatio
4.3.5 Tilanhallinta
4.3.6 Reaktiivisuus
4.3.7 Lifecycle-metodit (hooks)
4.3.8 Lomakkeet (forms)
4.3.9 Ulkoasukirjastot
4.3.10 Kommunikaatio palvelimen kanssa
4.3.11 Testaus
4.3.12 Versiopäivitykset
4.3.13 Skematiikka ja valmiskomponentit
Tehtävät

 

1 Opintojakson perustiedot

Frontend-sovelluskehitys (5op) kuuluu Jyväskylän Ammattikorkeakoulun (JAMK) Tietojenkäsittelyn koulutusohjelman (Tiko) vapaavalintaisiin ammattiopintoihin.

Opettaja Tommi Tuikka, tuito(at)jamk.fi

Muut perustiedot ovat opintojakson Moodle-työtilassa.

2 Ohjelmointiympäristö

Kurssilla käytetään ohjelmointikielenä Typescriptiä joka on vahvasti tyypitettyä Javascriptiä. Jos osaat Javascriptiä, on TS erittäin helppo oppia. Ohjelmointiympäristönä käytetään normaalia JS-ekosysteemiä ja kehitysvälineenä Visual Studio Code -editoria, eli ympäristö on täysin sama kuin edellisillä kursseilla. Tällä kurssilla ei toistaiseksi käytetä tehtävien ratkaisujen validointiin TDD -testejä, mutta kurssilla käytetyn sovelluskehyksen mukana tulevat kirjastot niiden toteuttamiseen.

3 Frontend-sovellus

Nykyaikainen web-sovellus jakautuu kahteen pääosaan: frontendiin ja backendiin. Frontend tarkoittaa web-selaimella eli asiakaspuolella suoritettavaa sovelluksen osaa, joka sisältää käyttöliittymän ja siihen liittyvää sovelluslogiikkaa. Backend on puolestaan palvelimella suoritettava sovelluksen osa, joka sisältää muuta sovelluslogiikkaa ja yhteyden tietokantaan, joka toimii sovelluksen tietovarastona. Molemmat edellä mainitut voivat jakautua edelleen pienempiin osiin arkkitehtuurista riippuen. Frontend ja backend voivat vaihtaa tietoja keskenään verkon yli asynkronisten HTTP-pyyntöjen avulla. Sovellusta jossa on sekä frontend että backend kutsutaan full-stack -sovellukseksi.

Frontend-sovellus ladataan tavallisesti palvelimelta asiakkaan selaimelle jossa se suoritetaan. Ylivoimaisesti suosituin frontend-ohjelmointikieli on Javascript, jolle on tuki kaikissa nykyaikaisissa selaimissa ja kaikilla yleisimmillä päätelaitteilla (W3Techs.com). Sovelluksen kehitysvaiheessa käytetään usein Typescriptiä, joka on JS:n vahvasti tyypitetty muunnos. Se muunnetaan ennen sovelluksen julkaisua selaimen ymmärtämäksi JS:ksi. Nykyaikaiset frontend-sovellukset sisältävät yleensä paljon JS/TS:ää, jolla on toteutettu sovelluksen toimintalogiikka. Ulkoasu on toteutettu HTML:llä ja CSS:llä. Frontend-sovellukset muodostuvat yleensä yhteen pakatuista ja tiivistetyistä koodipaketeista (bundle), joita voi olla yksi tai useampia.

Nykyaikaiset frontend-sovellukset voivat olla hyvin laajoja ja suurin osa sovelluksen koodista voi sijaita frontendissä (thick client). Perinteisissä web-sovelluksissa suurin osa koodista sijaitsi backendissä (thin client). Thick client -periaate mahdollistaa asiakaskoneiden lisääntyneen tehokkuuden hyödyntämisen.

Nykyaikaiset frontend-sovellukset toteutetaan yleensä niiden kehittämiseen tarkoitettujen sovelluskehysten/ohjelmakirjastojen avulla. Näistä yleisimmät ovat React, Angular ja Vue.

3.1 SPA-sovellus

SPA eli Single Page Application on sovellus joka toimii koko elinkaarensa ajan yhdellä sivulla. Käyttäjä lataa frontendin eli asiakassovelluksen joka esittää yhden web-sivun, ja sen jälkeen ei tapahdu enää sivunlatauksia vaan sivulla olevaa tietoa päivitetään joko asiakassovelluksesta itsestään tai palvelinpuolelta asynkronisesti. Tälläiset sovellukset voivat olla hyvinkin laajoja, vaikka näkyvillä on koko sovelluksen toiminnan ajan vain yksi ainoa sivu. Sivun sisäisistä linkeistä vaihtuu sivulle palanen kerrallaan, esim. sivun keskellä oleva sisältöalue. SPA-sovelluksia tehdään nykyaikaisilla frontend-sovelluskehyksillä ja -kirjastoilla.

PWA eli Progressive Web Application on SPA-sovellus, joka on optimoitu toimimaan erityisen hyvin mobiililaitteissa. Tavalliselle kannettavalle koneelle tehdyn SPA-sovelluksen voi varsin helposti muuntaa PWA:ksi. Käsittelemme PWA-sovelluksia tarkemmin kurssilla Mobiilisovelluskehitys web-teknologioilla.

SPA-sovellusten plussat:

+sulavampi ja nopeampi käyttökokemus
+mobiilisovelluksiin sopiva käyttökokemus (PWA)
+vähentää serveriltä hakemisen tarvetta
+hyödyntää paremmin asiakaskoneen resursseja
+soveltuu hyvin dynaamisten ja reaaliaikaisten sovellusten kehittämiseen

SPA-sovellusten miinukset (eivät juurikaan haittaa enää 2024):

-sovelluksen alkulataus voi olla hitaampi
-sovelluksen näkymiä voi olla vaikeampi hakea hakukoneilla
-linkitys ulkopuolelta sivun tiettyyn sisältöön voi olla hankalampaa
-saavutettavuus (esim. näkövammaiset) voi olla heikompi

SPA-sovellusten ongelmat ovat teknologian kehittyessä pääosin poistuneet kokonaan. SPA-sovellukset ovat vakiinnuttaneet asemansa runsaasti dynaamista ja reaaliaikaista sisältöä tarjoavien sovellusten kehityksessä. SPA-sovellusten ja perinteisten palvelimella suoritettavien web-sovellusten hyvät puolet voi yhdistää Server Side Rendering (SSR) -teknologian avulla. SSR:ää käytetään yleensä siten, että SPA-sovelluksen aloitusnäkymä on etukäteen renderöity palvelimella, jolloin se latautuu käyttäjälle välittömästi. Kun SPA-sovellus on viimeistään parissa sekunnissa latautunut selaimelle, esitetään selaimella renderöityjä näkymiä.

JAMstack on sovellusarkkitehtuuri, jossa periaatteena on frontend-koodin suoritus mahdollisuuksien mukaan palvelimella, ja frontend-koodista SSG-generaattorilla luotujen staattisten sivujen tarjoaminen. JAMstack on yleistynyt hieman vähemmän dynaamisten sovellusten, kuten CMS-käyttöliittymien kehityksessä. Web-arkkitehtuurioppaassa on käsite JAMstack suomeksi selitettynä. Kurssilla käytetyllä Angular-sovelluskehyksellä on helppoa toteuttaa SSR ja SSG eli JAMstackin peruspiirteet, valitsemalla sovelluksen luontivaiheessa Y, kun kysytään otetaanko SSR käyttöön.

3.2 Asynkroniset pyynnöt

Eräs nykyaikaisten frontend-sovellusten tärkeimmistä periaatteista on että niiden pitää toimia yhtä nopeasti ja sujuvasti kuin asennetun ohjelman, vaikka ne toimivat web-selaimessa ja tarvitsevat välillä dataa palvelimelta. Frontendissä esitettävät tiedot pyydetään siksi palvelimelta asynkronisesti. Asynkronisuus tarkoittaa sitä että odottamista vaativat toimenpiteet, esim. suuren tietomäärän haku tietokantapalvelimelta, suoritetaan taustalla ilman että muun koodin suorituksen tarvitsee pysähtyä odottamaan pyynnön valmistumista. Käyttäjä voi tällöin käyttää sivustoa vaikka pyydetty data olisi vasta tulossa sovellukseen.

Asynkroniset HTTP-pyynnöt toteutetaan käyttämällä XHR-oliota tai Fetch-metodia. Nämä ovat web-selaimen sisältämät olio ja metodi jotka toimivat vain selainympäristössä. Näitä käytetään asynkronisilla koodirakenteilla: callback, promise, async/await tai observable. Kolme ensimmäistä soveltuvat parhaiten yksittäisten asynkronisten tapahtumien käsittelyyn. Observable soveltuu sekä yksittäisten että jatkuvasti toistuvien asynkronisten tapahtumien (streamin eli tietovirran) käsittelyyn.


4 Angular

angular

Angular on Googlen kehittämä komponenttipohjainen frontend-sovelluskehys, jonka avulla tehdään erityisesti moderneja SPA-sovelluksia. Angularissa ohjelmointikielenä käytetään Typescriptiä, joka build-vaiheessa käännetään selaimen ymmärtämäksi Javascriptiksi. Angular kehittyy jatkuvasti, ja tätä kirjoitettaessa ollaan versiossa 18.x. Versioiden erot ovat yleensä pieniä ja päivittäminen uudempaan versioon ei ole aina tarpeellista. Tarvittaessa päivittäminen onnistuu kuitenkin varsin helposti.

Angular-sovellus muodostuu Esbuildilla pakatuista .js-, .html- ja .css -tiedostoista sekä mediaelementeistä. Sovellus ladataan palvelimelta käyttäjän koneen selaimelle kun käyttäjä pyytää sovelluksen etusivua. Angular-sovellus on harvoin palvelimista riippumaton. Yleensä ainakin käyttäjien yhteinen tietovarasto sijaitsee palvelimella, ja data välitetään palvelimelta Angular-sovellukseen ja toisinpäin. Myös autentikaatio ja raskaampi laskenta tapahtuvat palvelimella, johon frontend on tavallisesti yhteydessä API-rajapintojen välityksellä.

Miksi Angular?

Kurssilla käytetään perustelluista syistä frontend-sovelluskehyksenä Angularia. Tärkeimmät syyt ovat 1) Arkkitehtuuri - A niin kuin Arkkitehtuuri ja Angular, sekä 2) Opettavaisuus, eli hyödyllisyys yleisten sovelluskehityksen periaatteiden ja hyvien ohjelmointikäytänteiden oppimisessa. 3) Monipuolisten ominaisuuksiensa ja hyvän suorituskykynsä ansiosta Angular on paras vaihtoehto suurten ja monimutkaisten enterprise frontend -sovellusten kehitykseen.

Angular on sovelluskehys, toisin kuin vaikkapa React, Vue tai Svelte, jotka eivät ole sovelluskehyksiä vaan kirjastoja. Angularin avulla oppii hyvin yleisiä sovelluskehityksen arkkitehtuuri- ja suunnittelumalleja, ja yleistä sovelluskehysten toimintaa, mistä on hyötyä käytettäessä kaikkia erilaisia ohjelmointikieliä ja sovelluskehyksiä. Angularin perusteiden hallinta helpottaa siis minkä tahansa muun frontend- tai backend-sovelluskehyksen oppimista ohjelmointikielestä riippumatta. Angularin arkkitehtuuri perustuu olio-ohjelmointiin, mutta sen rakenneosien kehityksessä käytetään paljon myös funktionaalista ja reaktiivista ohjelmointityyliä. Angular ja erityisesti Typescript pakottavat kehittäjän käyttämään myös monia hyviä ohjelmointikäytänteitä, kuten muuttujien alustamista ja datan kuvaamista rajapintaluokkien avulla. Javascriptillä koodattaessa hyvien ohjelmointikäytänteiden noudattaminen on hankalampaa, ja tahtoo usein unohtua.

Jyväskylässä toimiva sovelluskehittäjä joutuu urallaan erittäin todennäköisesti tekemisiin C#:n, ja/tai Javan kanssa. Typescriptissä ja Angularissa on paljon samoja piirteitä kuin C#:ssa ja Javassa sekä niihin perustuvissa sovelluskehyksissä, joita ovat esim. ASP.NET (C#) ja Spring (Java). Myös muilla kielillä kehitettyjen sovelluskehysten oppimisessa on Angularin tuntemisesta apua. Yleisesti parhaana Nodejs backend-sovelluskehyksenä pidetty NestJS, on arkkitehtuuriltaan ja muultakin toiminnaltaan lähes suora kopio Angularista. Myös Laravel (PHP) ja Django (Python) sisältävät Angularin kanssa yhteisiä piirteitä.

Angularin avulla voit oppia perustekemisen kautta mm. luokka/olio-arkkitehtuurin, MVC/MVVM-arkkitehtuurin, komponenttiarkkitehtuurin, dependency injectionin, template patternin, service patternin, observable patternin, decorator patternin, lazy-loading patternin ja mediator patternin. Muut frontend-kirjastot eivät ole yhtä opettavaisia kuin Angular. Arkkitehtuuri voi unohtua kokonaan, tai se pitää toteuttaa itse. Tuloksena voi olla laadultaan hyvin vaihtelevia arkkitehtuuriratkaisuja eri sovelluksissa. Angularissa useimmat arkkitehtuuriratkasut ovat jo ennalta olemassa.

Ulkopuolisten ns. "kolmannen osapuolen" ohjelmakirjastojen käyttö voi muodostua useissa frontend-kirjastoissa ongelmaksi, sillä niiden laatu, soveltuvuus ja elinkaari pitää itse arvioida. Elinkaari voi muodostua hyvinkin lyhyeksi, jos kirjaston kehitystyö päättyy. Runsas kolmannen osapuolen kirjastojen käyttö voi lisätä myös sovelluksen tietoturvariskiä. Nämä ovat Angularissa pienempiä ongelmia kuin monissa muissa frontend-kirjastoissa, sillä Google ylläpitää useita Anngularin lisäkirjastoja, joita kehittäjät voivat sekä elinkaaren että turvallisuuden puolesta huoletta käyttää.

Kaikissa Angular-sovelluksissa toistuvat yhteiset piirteet ja arkkitehtuuri, joiden ansiosta kehittäjän on helppo ymmärtää muiden Angular-kehittäjien tekemää koodia. React-kehityksessä asianlaita on harvemmin näin, sillä eri kehittäjät käyttävät usein erilaisia kirjastoja ja arkkitehtuuriratkaisuja. Esim. Reactilla ja Vuella on tehty paljon sovelluksia, joiden jatkokehitys tai ylläpito on todella hankalaa muille kuin alkuperäisille kehittäjille.

Kaikissa JS/TS frontend-sovelluskehyksissä ja -kirjastoissa on myös paljon yhteisiä piirteitä, ja yhden välineen osaaminen helpottaa huomattavasti muiden opettelua. Niinpä Angularin opettelun jälkeen on varsin helppoa ottaa haltuun esim. React, vaikkapa tämän kurssin avulla. Hyvän frontend-sovelluskehittäjän pitäisi ehdottomasti tuntea vähintään pari, kolme erilasta frontend- sovelluskehystä tai sovelluskehityskirjastoa, ja osata arvioida ja vertailla niiden ominaisuuksia. Sekä Angularin että Reactin peruspiirteiden tunteminen on hyödyllistä, sillä ne edustavat hieman erilaisia lähestymistapoja frontend-sovelluskehitykseen, ja molemmilla lähestymistavoilla on omat hyvät ja huonot puolensa.

Sovelluskehys tarjoaa rakenteen ja säännöt

Kun opiskelija tutustuu ensimmäisen kerran johonkin web-sovelluskehykseen, ensivaikutelma on yleensä se, että onpa monimutkainen tapa tehdä yksinkertainen sovellus. Sovelluskehysten edut eivät kuitenkaan tule esille pienissä ja yksinkertaisissa sovelluksissa, joita tavallisesti käytetään opiskeluvaiheessa ensimmäisinä esimerkkeinä. Angular on erinomainen esimerkki sovelluskehyksestä, jonka edut tulevat esille erityisesti vasta laajemmissa sovelluksissa, joiden kehitykseen ja ylläpitoon osallistuu useita kehittäjiä. Angular tarjoaa kaikki frontend-sovelluskehityksen välineet yhdessä paketissa, jonka Googlen kehittäjät ovat rakentaneet niin, että kaikki toimii, kunhan käytetään Angularin määrättyjä suunnitteluperiaatteita ja arkkitehtuurimalleja. Angular onkin luonteeltaan "opionated", eli asiat pitää tehdä ennalta määritellyllä tavalla eikä kehittäjälle anneta liikaa omia vapauksia. Yleensä ohjelmistoprojektit onnistuvatkin paremmin, kun noudatetaan ennalta sovittuja sääntöjä.

Nykyaikaiset sovelluskehykset, kuten Angular, sisältävät uudelleenkäytettäviä moduuleja ja komponentteja, joita voi tuoda muista sovelluksista, irroittaa sovelluksesta ja siirtää toiseen sovellukseen. Komponentit ovat yksiköitä, joita voidaan helposti testata yksikkötesteillä. Lisäksi ulkoasu (HTML, CSS) ja sovelluslogiikka (TS -koodi) on erotettu toisistaan eri tiedostoihin. Angular noudattaa erittäin vahvasti Separation of Concerns (SoC) -periaatetta. Lisäksi Angular käyttää suunnittelumalleja (design patterns) jotka toistuvat aina samakaltaisina ja tekevät esim. tiedonsiirrosta komponenttien välillä vakiomuotoista ja järkevää. Angular on MVVM -sovelluskehys. Angularin suurin vahvuus ovat sen tarjoamat standardoidut arkkitehtuuriratkaisut, jotka ovat sitä tärkeämpiä, mitä laajemmasta ja monimutkaisemmasta sovelluksesta on kysymys.

Standardoidun arkkitehtuurin tarjoavan sovelluskehyksen vastakohta on ns "spaghettikoodi" jossa ei ole rakennetta, eikä yleisesti sovittuja käytänteitä. Paljon tehdään myös sovelluksia, joissa on kehittäjän itsensä suunnittelema arkkitehtuuri, ja paljon kehittäjän valitsemia kolmannen osapuolen kirjastoja. Tässäkin tapauksessa yleisesti sovitut käytänteet useimmiten puuttuvat, ja henkilön joka ei ole tehnyt sovellusta, on vaikea ymmärtää koodia. Tämän tyyppisiä sovelluksia voi olla erittäin vaikea muokata, jatkokehittää, ylläpitää ja testata.

Sovelluskehysten suorituskyky

Frontend-sovelluskehysten ja -kirjastojen suorituskykyä eli nopeutta/tehokkuutta mitataan kolmella mittarilla: 1) Sovelluksen käyttöliittymän renderöintioperaatioiden nopeus, 2) Sovelluksen latautumisnopeus, 3) Sovelluksen muistin käyttö. Viralliset mittaustulokset ovat tässä. Elokuussa 2024 Angular (v18) oli keskitasoa nopeampi, ja esim. React (v18.2) oli selvästi hitaampi.

Mittauksissa ei ole otettu huomioon sitä, että latautumisnopeutta (first contentful paint) ja muistin käyttöä on mahdollista parantaa aivan huikeasti defer-lohkojen, lazy-loadingin, SSR:n tai PWA-cachen avulla. Näiden käyttöön Angular sisältää erinomaiset kirjastot.

4.1 Angular -sovelluksen luonti, julkaisu ja debuggaus

Ohjelmointiympäristön säätäminen kuntoon:

1. Asenna Angular CLI -komentorivityökalu komennolla: npm i -g @angular/cli, ja tarkista komennolla ng version että asennus onnistui. Jos asennus ei onnistunut, voi syynä olla vanhentunut Nodejs:n versio. Tarkista asia täältä ja asenna tarvittaessa uudempi Noden versio. Voit tarvittaessa päivittää Angular-CLI:n komennolla: npm install -g @angular/cli@latest.
2. Asenna VSCodeen pari lisäosaa: Angular Language Service tarjoaa koodin täydennyksen templaattisivuille ja Angular Snippets generoi usein toistuvia koodinpätkiä. Katso tarvittaessa lisäohjeita: Using Angular in Visual Studio Code.
3. Asenna Chromeen (tai Firefoxiin) Angular DevTools -lisäosa.

4.1.1 Sovelluksen luonti

Angular-projektin projektipohja (boilerplate) syntyy Angular CLI -komentorivityökalun new -komennolla. Angular CLI:n komennot ovat muotoa: ng komento argumentit optiot.

Uusi projekti joka sisältää yksikkötestikirjastot ja testien tiedostot:

ng new projektinnimi

Uusi mahdollisimman pienikokoinen projekti ilman testejä (käytetään yleensä tätä):

ng new projektinnimi --minimal -t=false -s=false

Optiolla --minimal  testikirjastoja ei asenneta ja komponenteille ei luoda automaattisesti testitiedostoja. Optioilla -t  ja -s  asetetaan inline-template- ja inline-style -asetusten arvoiksi false, jolloin komponenttien HTML- ja CSS-osille luodaan erilliset tiedostot. Minimiasennus tekee ilman näitä optioita inline-komponentteja, joissa kaikki komponentin osat ovat samassa tiedostossa, mikä ei ole hyvän SoC-käytänteen mukaista.

Edelliset komennot luovat sovelluksen, jonka komponentit eivät ole ole moduulin sisällä. Jos haluat luoda modulaarisen sovelluksen, kirjoita edellä mainittujen optioiden lisäksi tämä ensimmäiseksi optioksi heti projektin nimen perään:

--standalone false

Uutta projektia luotaessa kysytään lisäksi 1) Minkä tyyppiset tyylitiedostot, CSS, Less vai Sass. Vastataan CSS. 2) Otetaanko käyttöön SSR eli Server Side Rendering ja SSG eli Static Site Generator. Vastataan No, mutta oikeasti julkaistavissa sovelluksissa näitä ominaisuuksia voidaan tarvita. Asetuksia voi vaihtaa myöhemmin.

Mene syntyneeseen kansioon ja aja sovellus testiserverillä:

ng serve -o

Option -o ansiosta sovellus avautuu suoraan selaimeen. Testiserverillä sovellusta ajetaan vain muistissa oletuksena portissa 4200, koska sitä ei ole vielä rakennettu (build). Tämä kuitenkin riittää kehitysvaiheessa. Testiserveri sammutetaan CTRL-C:llä. Kannattaa käydä lisäämässä optio -o package.json -tiedoston "start" -skriptiin. Sen jälkeen npm start -komento suorittaa komennon ng serve -o.

Angular CLI sisältää edellisten komentojen lisäksi monia kehitystyötä helpottavia komentoja, kuten koodirunkojen luontia (generate eli g) ja kirjastojen asennusta (add). Uusi komponentti syntyy seuraavasti:

ng g c komponentinnimi

Komennolla ng help näet yleisimpiä komentoja selityksineen.

4.1.2 Sovelluksen julkaisu

Kehitysvaiheessa Angular-sovellus rakennetaan eli buildataan vain muistiin, ja sovellusta ajetaan muistista. Julkaisu vaatii oikean buildauksen fyysisiksi tiedostoiksi ja tiedostojen siirron julkaisupalvelimelle. Buildaus eli rakentaminen tarkoittaa Typescriptin muuttamista selaimen ymmärtämäksi Javascriptiksi ja JS:n, HTML:n, CSS:n, kuvien yms. pakkaamista muutamaan tiiviiseen pakettiin (bundle). Buildattu sovellus syntyy projektin dist -kansioon komennolla

ng build

Kun siirrät buildatun sovelluksen julkaisupalvelimelle johonkin kansioon, pitää buildatun sovelluksen index.html:n base-tagin href-attribuuttiin vaihtaa kansiopolku. Oletuksena on, että sovellus julkaistaan palvelimen juureen eli base href="/". Jos sovellus laitetaan vaikkapa kansioon "myfolder", pitää kansiopolun olla base href="/myfolder/". Omalla koneellasi Angular tekee buildin kansioon dist/projektinnimi/browser. Jos haluat kokeilla buildattua sovellusta esim. Live Serverillä, vaihda buildatun sovelluksen index.html:ään base href="/dist/projektinnimi/browser/".

4.1.3 Sovelluksen debuggaus

Komponenttien ja servicejen tilaa (state), eli käytännössä muuttujien arvoja, on kätevintä seurata selaimen Developer Tools -konsolista. Havainnollisin työkalu tähän on Chromen (ja Firefoxin) Angular DevTools -lisäosa.

Angular-sovelluksen TS-koodia voidaan debugata VSCoden sisäänrakennetulla debuggerilla samalla tavalla kuin JS-koodia. Koska Angular-koodi suoritetaan selaimessa eikä Nodejs-moottorilla, pitää debuggausta varten asentaa VSCodeen Javascript Debugger -lisäosa, eli VSCodessa käytetään selaimen debuggeria. Debuggausohje. Angular-projektin launch.json voisi näyttää vaikkapa tältä, kun mukana on skipFiles -määre jolla estät debuggeria menemästä node_modules -kansion tiedostoihin.

Perinteinen console.log() TS -koodissa ja tap() -metodi reaktiivisessa koodissa, esim. observablen käsittelyssä, toimivat yksinkertaisissa debuggaustapauksissa oikein hyvin.

4.2 Angular-sovelluksen rakenneosat ja toimintaperiaate

4.2.1 Rakenneosat

Komponentit ovat sovelluksen yleisimpiä rakenneosia. Ne ovat Typescript-luokkia (esim. app.component.ts). Komponentin sisältö jakautuu kolmeen osaan: 1) Luokkaosa, joka sisältää sovelluslogiikan, 2) HTML-templaatti, joka sisältää käyttöliittymälogiikan ja 3) CSS-tiedosto. Nämä kolme osaa sijaitsevat yleensä omissa tiedostoissaan. HTML-templaatti ei sisällä pelkkää HTML:ää, vaan myös Angularin omaa templaattisyntaksia, joka mahdollistaa monipuolisen käyttöliittymälogiikan.

Komponentit voivat olla moduulin (esim. app.module.ts) sisällä. Uusi Angular-sovellus ei ole oletuksena modulaarinen, vaan se pitää tarvittaessa määritellä modulaariseksi luontivaiheessa. Modulaarisuutta tarvitaan yleensä vain suurissa sovelluksissa, joissa on tarpeen ryhmitellä omiin moduuleihinsa komponentteja ja muita rakenneosia, jotka kuuluvat samaan kokonaisuuteen.

Angular-sovelluksessa on aina pääkomponentti (app.component.ts), jonka sisällä muut komponentit ovat. Komponentin tarvitsemat riippuvuudet (esim. kirjastomoduulit ja muut komponentit) sijoitetaan komponentin imports-taulukkoon. Jos riippuvuuden tulee olla käytössä koko sovelluksessa, se sijoitetaan app.config.ts -tiedostoon. Modulaarisessa sovelluksessa riippuvuudet ovat moduulin imports-taulukossa.

Komponenteilla voi olla sovelluksessa eri rooleja. Tyypillisimmät roolit ovat 1) esittävä komponentti jonka päätarkoituksena on luoda käyttöliittymä, 2) toiminnallinen komponentti, jonka päätarkoituksena on suorittaa frontend-sovelluksen sovelluslogiikkaa ja 3) säiliökomponentti jonka tarkoituksena on rakenteen luominen siten, että se sisältää muita komponentteja. Yleensä samalla komponentilla on jossain määrin sekä esittävä että toiminnallinen rooli. Täysin puhtaasti esittävät tai toiminnalliset komponentit ovat harvinaisempia.

Angular-komponentit (ja moduulit) käyttävät dekoraattoreita (eli annotaatioita) jotka ovat @-merkillä alkavia funktioita. Luokan edessä oleva dekoraattori (decorator suom. koristelija), ottaa määrittelytietoja sisältävän olion argumentikseen, ja tekee luokasta määrittelytietojen perusteella esim. komponentin tai moduulin. Dekoraattori kuuluu Typescriptin syntaksiin, ja sitä käytetään paljon perinteisissä olio-ohjelmointikielissä kuten Javassa ja C#:ssa.

Tyypillisimmät rakenneosat:

Kun Angular-sovellukseen lisätään edellä mainittuja rakenneosia, pitää ne lisätä kyseisiä rakenneosia käyttävän komponentin imports-taulukkoon. Jos rakenneosa on käytössä koko sovelluksessa, se sijoitetaan app.config.ts -tiedostoon. Mikäli sovellus on modulaarinen, lisätään rakenneosat moduulin imports-taulukkoon.

angular_basic_architecture

Kaaviokuva Angular-sovelluksen perusrakenteesta. Komponentti muodostuu luokasta, metadatasta ja templaatista. Lisäksi kuvassa näkyvät komponenttiin injektoitu service, templaatissa käytetty direktiivi ja reititys kahteen muuhun komponenttiin. Event-bindingin ja property-bindingin suunnat komponentissa on myös esitetty. Angular-sovelluksen rakenteen ja komponenttien hierarkian voi hahmotella esim. piirtämällä, ennen kuin aloittaa sovelluksen kehittämisen.

4.2.2 Toimintaperiaate

Angular-sovelluksen voidaan sanoa noudattavan MVVM-arkkitehtuurimallia. Modelin muodostavat data ja dataa kuvaava rajapintaluokka. View eli näkymä on komponentin HTML-osa. ViewModel on komponentin TS-luokka, sillä TS-luokan muuttujiin haettu data välitetään siitä Viewiin data-bindingin avulla.

Angularin model muodostuu datasta ja sen kuvauksesta. Datan kuvaus on yleensä erillisessä rajapintaluokassa, joka kuvaa datan rakenteen ja tietotyypit. Itse data voi olla komponentin sisällä, ulkoisessa tiedostossa tai palvelimella. Yleensä data tulee palvelimelta, mikä on usean käyttäjän web-sovelluksessa ainoa mahdollinen ratkaisu. Palvelinpuolen ohjelmisto hakee datan tietokannasta ja välittää sen API-rajapinnan kautta JSON-muodossa Angular-sovellukselle. Angular-sovelluksen Service vastaanottaa datan HttpClient-olion avulla ja välittää datan eteenpäin komponenteille.

angtoiminta

Kuvassa on esitetty datan kulku full-stack -sovelluksessa jossa on Angular-frontend. Tieto kulkee Angular-sovelluksen komponentin HTML-osasta palvelinpuolella sijaitsevaan tietokantaan ja toisinpäin.

Angular-koodaus perustuu Angularin omiin käytänteisiin ja sääntöihin, jotka tulee tuntea jotta koodaus onnistuisi. Koodauksessa on noudatettava Angularin tarjoamia arkkitehtuuriratkaisuja. Sääntöjen oppimisen jälkeen sovelluskehitys on varsin loogista. Angular sisältää paljon valmiita, sisäänrakennettuja rakenneosia, kuten määrättyihin tarkoituksiin luotuja direktiivejä, filttereitä ja moduuleja, joiden käyttöohjeet ovat dokumentaatiossa.

4.2.3 Esimerkkejä
Modulaarisen kontaktimuistion vaiheet:
  1. ang-contactapp1 - Tehdään lista johon haetaan data tiedostosta.
  2. ang-contactapp2 - Tehdään datan haku palvelimelta ja lomake jolla lisätään uutta dataa palvelimelle servicen välityksellä.
  3. ang-contactapp3 - Tehdään muokkauskomponentti, jossa dataa voidaan muokata ja poistaa.
  4. ang-contactapp4 - Tehdään lisäyslomakkeen validointi valmiilla direktiiveillä ja reaktiivinen haku oman pipen avulla.
  5. ang-contactapp5 - Tehdään responsiiviset Bootstrap-tyylit.

Kontaktimuistion uudempi versio, jossa on signaaleilla toteutettu reaktiivinen haku:

4.3 Frontend-sovelluksen peruspiirteet Angularissa

4.3.1 Reititys

Reititys on kaikkien SPA-sovelluskehysten perusominaisuus, joka mahdollistaa näkymien vaihtamisen SPA-sivulle. Reititys syntyy automaattisesti jokaiseen Angular-CLI:llä luotuun projektiin. Angularin reititys muodostuu kolmesta yksinkertaisesta osasta. 1) Reititystiedosto (tai reititysmoduuli modulaarisessa sovelluksessa) sisältää taulukon jossa ovat reittioliot. 2) HTML-templaatissa on <router-outlet>-tagi siinä paikassa jossa näkymät vaihtuvat 3) Navigointi tapahtuu routerLink -direktiiviin (linkit) tai navigate()-metodin (nappi) avulla. Reitissä voidaan välittää parametreja jolloin linkki ja parametrit ovat taulukossa. Reitti voidaan suojata Guard -providerilla.

4.3.2 Data binding

Data binding tarkoittaa kahden eri paikassa olevan dataviittauksen sitomista toisiinsa niin, että jos dataa muutetaan yhdessä paikassa, se muuttuu samalla myös toisessa paikassa. Data binding voi olla Angularissa yksisuuntaista ja kaksisuuntaista. Komponentin templaattiin tehty muutos voi aiheuttaa muutoksen luokassa ja luokassa tehty muutos voi aiheuttaa muutoksen templaatissa. Two-way data binding tarkoittaa sitä, että muutos tapahtuu molempiin suuntiin. Angularissa käytetään kuitenkin yleensä yksisuuntaista data bindingia, koska Two-way data binding paljon käytettynä hidastaa sovellusta. Angularissa on omat merkintätapansa eri tyyppisille data bindingeille. Yleisimmät bindaukset ovat:

  1. Interpolation binding: luokassa oleva muuttuja sidotaan yksisuuntaisesti {{muuttuja}} -merkintään templaatissa. Yleisin tapa välittää dataa luokasta templaattiin.
  2. Event binding: templaatissa oleva event eli tapahtuma sidotaan yksisuuntaisesti luokassa olevaan metodiin merkinnällä (event) = metodi(). Event, esim. click, laukaisee metodin suorituksen.
  3. Two-way binding: templaatissa, useimmiten lomakkeella, oleva data sidotaan kaksisuuntaisesti luokassa olevaan muuttujaan merkinnällä [(ngModel)]="muuttuja".
  4. Property binding: luokassa oleva muuttuja sidotaan yksisuuntaisesti templaatissa olevaan arvoon x. Merkintä templaatissa on [x] = "muuttuja". Yleisin tapaus on, että äitikomponentin muuttuja sidotaan lapsikomponentin muuttujaan x. Tällöin data siirtyy äitikomponentista lapsikomponenttiin (input). Kyse on siis Angularin "propseista".
  5. Attribute binding: HTML-attribuutti sidotaan muuttujaan ja se saa muuttujassa olevan arvon. [attribuutti] = "muuttuja". Hakasulkumerkintä on sama kuin property bindingissa.
  6. Class binding: CSS-tyyli sidotaan ehtoon, ja jos ehto on true, tyyli tulee voimaan. [class.tyylinnimi] = "ehto". Hakasulkumerkintä on sama kuin property bindingissa.

4.3.3 Dependency injection

Angularin tärkeä periaate on, että komponentit ja servicet ovat löyhästi sidottuja tosiinsa. Esimerkiksi komponenttiin pitää olla mahdollista vaihtaa service niin, että ei tarvitse tehdä luokan (class) koodiin mitään muutoksia. Tämä on mahdollista Dependency Injectionin eli DI:n avulla. Injektio voidaan tehdä komponenttiin tai serviceen kahdella eri tavalla: konstruktorin argumenttina tai inject-funktiolla.

4.3.4 Komponenttien välinen kommunikaatio

Komponenttien välinen kommunikaatio voidaan Angularissa toteuttaa monella eri tavalla. 1) @Input ja @Output -dekoraattoreita käytetään merkkaamaan liikkuuko data äitikomponentista lapsikomponenttiin (@Input) vai lapsikomponentista äitikomponenttiin (@Output). Data siirtyy @Input-tapauksessa property bindingin avulla ja @Output-tapauksessa event-bindingin avulla. 2) Serviceä voidaan käyttää välittämään dataa komponentista toiseen. 3) Mediator-pattern on komponenttien välisen kommunikaation malli jossa yksi komponentti toimii kahden tai useamman löyhästi kytketyn komponentin välisen viestinnän välittäjänä (mediator). 4) @ViewChild -dekoraattoria voidaan käyttää komponentin luokassa (.ts-luokka) välittämään luokkaan komponentin viewissä (HTML-templaatti) esiintyvien lapsikomponenttien ominaisuudet.

Pienissä Angular-sovelluksissa edellä mainitut ratkaisut komponenttien väliseen kommunikaatioon toimivat hyvin. Servicessä voidaan säilyttää koko sovelluksen tilaa, kuten esim. tietoa siitä onko sovellukseen loggauduttu vai ei (kts. tehtävä7). Komponentit saavat tämän tiedon serviceltä. Suuremmissa sovelluksissa, joihin tulee dataa useista eri lähteistä, on yleensä järkevää käyttää koko sovelluksen tilanhallintaa varten luotua "tilasäiliötä", eli storea, jonka välityksellä komponettien välinen kommunikaatio tapahtuu.

4.3.5 Tilanhallinta

Frontend-sovelluksen tilanhallinta tarkoittaa yksinkertaistettuna sitä, että komponentit voivat käyttää yhteisiä muuttujia eli yhteistä tilaa (tila on muuttujissa), joka sijaitsee komponenttien ulkopuolella omassa tiedostossaan. Ajattelepa vaikka sovellusta jossa on tuotekomponentti, ostoskorikomponentti ja maksukomponentti. Kun valitset tuotteen ostoskoriin, pitää tuotteen hinnan siirtyä tuotekomponentista ostoskori-komponenttiin. Valittujen tuotteiden määrän pitää vähentyä tuotekomponentissa ja lisääntyä ostoskorikomponentissa. Ostotapahtuman jälkeen määrä vähenee pysyvästi. Kun siirryt maksukomponenttiin, pitää sielläkin näkyä tuotteiden hinnat ja lukumäärä, mitkä saadaan ostoskorista. Komponenttien välisen kommunikaation hallinta voi muuttua sovelluksen laajentuessa todella hankalaksi ilman komponenttien yhteistä tilaa, jossa edellä mainitut tuotteiden lukumäärät ja hinnat voisivat sijaita.

-ang-storeservice - esimerkki, joka demoaa tilanhallinnan merkitystä sovelluksessa, jossa tilan muutoksilla komponenteissa on paljon vaikutuksia muiden komponenttien tilaan. Esimerkissä on tehty servicestä signaalien avulla yksinkertainen reaktiivinen store.

Tilanhallintaan on muutamia tapoja, joista tässä neljä tyypillisintä:

1) Angularissa yksinkertainen tilanhallinta voidaan toteuttaa servicejen avulla, kuten tehtävässä 7 on tehty. Serviceistä voidaan tehdä myös kehittyneempiä reaktiivisia tilasäiliöitä, kuten ang-storeservice -esimerkissä on esitetty.

2) Localstorage ja sessionstorage soveltuvat myös yksinkertaiseen tilanhallintaan. Tästä on esimerkkinä localstoragen käyttö tehtävässä 6. Ne tosin tallentavat sovelluksen tilan pysyvästi selaimelle, kun normaalisti tilanhallinta tapahtuu sovelluksen varaamassa muistissa. Tilanhallinta selaimen tarjoamassa varastossa toimii vain pienillä tietomäärillä, ja on hitaampaa kuin sovelluksen muistissa tapahtuva tilanhallinta, eikä mahdollista tiedon prosessointia tietosäiliössä.

3) Tilanhallintakirjastot sisältävät edistyneempiä ominaisuuksia vaativampaan tilanhallintaan. Tilanhallintakirjaston avulla luodaan muistiin store eli "säiliö", jossa säilytetään koko sovelluksen tilaa. NgRx Store on Angularin tunnetuin tilanhallintakirjasto. Store helpottaa tiedon välittämistä komponenteille, varsinkin kun komponentteja on paljon, niillä on monimutkainen hierarkia ja sovellukseen tulee asynkronista dataa monista eri lähteistä, kuten esim. pilvipalveluista. Store on ns. "single source of truth", eli komponentit saavat sieltä aina varmasti ajankohtaisen datan. Suljettaessa sovellus, store voidaan tallentaa myös pysyväismuistiin eli tietokantaan tai localstorageen. Jos sovelluksessa joudutaan tekemään erittäin paljon HTTP-pyyntöjä esim. ulkoisiin tietolähteisiin, voi store toimia välimuistina, jonka avulla voidaan vähentää pyyntöjen määrää. Storea voidaan käyttää myös datan filtteröintiin, jolloin voidaan kätevästi luoda datasta erilaisia näkymiä komponentteihin.

store

4) NgRx SignalStore -kirjastolla voidaan toteuttaa yhtä vaativia tilanhallintaratkaisuja kuin NgRx Storella, mutta vähemmällä koodilla ja yksinkertaisemmin. Signaalistore soveltuu yksinkertaisemman rakenteensa vuoksi myös pienempiin sovelluksiin. NgRx SignalStore näyttäisi olevan nousussa Angularin suosituimmaksi tilanhallintaratkaisuksi. Esim. tässä artikkelissa perustellaan, miksi sitä kannattaisi käyttää.

Esim. Reactissa tai Sveltessä store on hyvin pieniä sovelluksia lukuun ottamatta yleensä välttämätön (esim. Redux Store, johon NgRx Store perustuu). Angularissa näin ei ole, koska servicet ja dependency injection mahdollistavat yksinkertaisen tilanhallinnan. Store monimutkaistaa sovelluksen rakennetta, minkä vuoksi sen käyttöä kannattaa harkita laajemmissa sovelluksissa tilanteen mukaan.

4.3.6 Reaktiivisuus

Reaktiivisuus toteutetaan Angularissa RxJS:n ja signaalien avulla. Reaktiivinen ohjelmointi on ohjelmointia, jossa käsitellään asynkronisesti virtaavaa tietoa (asynchronous data streams). Reaktiivisuuteen kuuluu myös se, että muutokset muuttujissa välittyvät suoraan niistä riippuviin muuttujiin, jotka tarkkailevat muutoksia jatkuvasti (observer-observable -periaate).

Angularissa on sisäänrakennettuna RxJS, joka on Javascriptin reaktiivinen laajennos. Esimerkkejä reaktiivisista toiminnoista ovat: reaktiivinen kommunikaatio palvelimen kanssa, reaktiivinen tapahtumankäsittely (event stream) ja reaktiiviset lomakkeet. Angularin HttpClient, jota käytetään kommunikaatioon palvelimen kanssa, palauttaa aina observablen, eli sen toiminta on reaktiivista. Kun tieto tulee observablena, se voi olla yksittäinen tieto, mutta myös useista peräkkäisistä tiedoista koostuvaa virtaa eli streamia. Angularissa voi käyttää tiedon hakuun palvelimelta myös fetch()-metodia, joka palauttaa promisen, mutta fetch ei pysty käsittelemään tietovirtaa eli streamia, vaan ainoastaan yksittäisiä tietoja.

Signaalit ovat reaktiivisia muuttujia, joita voidaan luoda yksinkertaisesti const nimi = signal('arvo') -lauseella. Arvo saadaan ulos signaalista getterimetodilla nimi(). Signaalit ovat uusin ja tehokkain tapa kehittää reaktiivisia sovelluksia. Signaali on siis muuttuja joka sisältää arvon ja ilmoituksen (notifikaation) arvon muutoksesta. Signaalien avulla voidaan kehittää sovelluksen reaktiivisuutta hyvin yksityiskohtaisesti. Signaaleilla voidaan myös korvata RxJS:n toimintoja ja reaktiivisia lomakkeita. Käytännön esimerkkejä signaalien käytöstä.

4.3.7 Lifecycle-metodit (hooks)

Lifecycle-metodit (hooks) ovat metodeja, jotka suoritetaan automaattisesti jossain komponentin elinkaaren vaiheessa. Näiden avulla voidaan automatisoida toimintoja, jotka liittyvät tiettyyn komponentin elinkaareen vaiheeseen. Esim. ngOnInit() suoritetaan kun komponentti on alustettu eli se on saanut alkuarvonsa, ja ngOnDestroy() suoritetaan juuri ennen kuin komponentti poistetaan muistista. Yleisin lifecycle-metodin käyttökohde on datan haku servicestä komponenttiin komponentin ngOnInit() -metodissa.

4.3.8 Lomakkeet (forms)

Lomakkeet voidaan toteuttaa Angularissa kahdella eri tavalla:

1) Template-driven -lomakkeen tietomalli määritellään templaatissa. Lomakkeesta tehdään ngForm -direktiivillä Angularin lomake, ja ngModel-direktiivi tekee lomakkeen input-kentästä osan Angularin tietomallia. Lomakkeen data vastaanotetaan luokkaan (ngSubmit)-eventin bindauksella. Laskin-esimerkissä ollut two-way-bindausta käyttänyt lomake on yksinkertaisin esimerkki template-driven -lomakkeesta. Template-driven -lomake on tavallisempi lomaketyyppi.

2) Reaktiivinen lomake eroaa template-driven lomakkeesta siten, että sen tietomalli määritellään Typescript-luokassa. Lomake-elementit ovat olioita jotka voivat toimia observableina ja emitoida dataa reaktiivisesti. Reaktiivista lomaketta voidaan käyttää tavallisen lomakkeen tapaan, mutta se on varsinaisesti tarkoitettu sellaisiin tapauksiin, joissa lomakkeelta tulevaa dataa pitää käsitellä tietovirtana eli streamina.

Lomakkeet validoidaan Angularin sisäänrakennetuilla tai itse tehdyillä direktiiveillä. Valmiit eli sisäänrakennetut direktiivit riittävät useimpiin tapauksiin.

4.3.9 Ulkoasukirjastot

Bootstrap ja Material Designiin perustuva Angular Material ovat yleisimmät CSS-frameworkit, joita käytetään Angular-sovellusten ulkoasun kehitykseen. CSS-frameworkit käyttävät edistyneempiä CSS-tekniikoita eli CSS-laajennoksia, joilla voi lisätä ohjelmoimalla "älykkyyttä" CSS:ään. Yleisimpiä ovat SASS ja LESS. CSS-frameworkit sisältävät monimutkaisempia käyttöliitymäefektejä varten yleensä myös JS-kirjastoja.

Bootstrap on eniten käytetty CSS-framework. Sen avulla on helppoa toteuttaa responsiivinen tai mobiilisivusto. Bootstrap sisältää sekä CSS- että JS-kirjastot. Ilmaisia Bootstrap -teemoja voi ladata vaikkapa sivustolta startbootstrap.com.

Material Design on laajempi kokonaisuus kuin pelkkä CSS-framework, jollainen toki sisältyy siihen. MD sisältää ohjeistuksen, komponentit ja työkalut UI-kehitykseen eri frontend-sovelluskehyksille ja mobiilialustoille. MD on siis käyttöliittymien hyvät käytänteet kokoava "käyttöliittymäohjeistus". Angular Material on MD:n Angularia varten tehty valmiita käyttöliittymäkomponentteja sisältävä toteutus. Material Design Lite on MD:n "kevytversio" jota ei ole sidottu mihinkään sovelluskehykseen kuten esim. Angulariin, vaan sitä voi käyttää perinteiseen tyyliin linkittämällä kirjasto sivustolle ja lisäämällä MD-tyylejä elementeille.

Muita yleisiä CSS+JS ulkoasukirjastoja ovat esim. Foundation ja Nebular. Ulkoasuja tehdään paljon myös puhtaalla CSS:llä ilman erillisiä kirjastoja yhdistämällä Flexbox ja CSS Grid.

-W3Schools Bootstrap-tutorial
-MD Developer tutorials

Kumpaa ulkoasukirjastoa kannattaa käyttää: Bootstrapia vai Materialia? Kirjastot tarjoavat käytettävyyden näkökulmasta hieman erilaisia käyttöliittymätyylejä. Bootstrapissa erilaisia tyylejä on enemmän, mutta ne eivät ole ehkä ihan niin "cooleja" kuin Materialissa. Jos komponentit ovat jo valmiita, niin Bootstrap-tyylien sijoittaminen olemassa oleviin komponentteihin on helppoa. MD tarjoaa paremman tuen, kun tarkoituksena on rakentaa sovelluksen käyttöliittymä valmiista käyttöliittymäkomponenteista. Bootstrapia on yksinkertaisempi säätää omiin tarkoituksiin sopivaksi kuin MD:tä.

Bootstrap ja Angular

Yleisin tapa ottaa käyttöön Bootstrap-peruskirjasto Angular-sovelluksessa on seuraavanlainen: 1) npm i bootstrap 2) lisätään Bootstrapin .css- ja .js -kirjastojen polut projektin juuressa olevan angular.json-tiedoston "styles" ja "scripts" -taulukoihin (tässä malli). Olemassa olevien Angular-komponenttien HTML-elementteihin lisätään sen jälkeen Bootstrapin tyylejä. Tarkempi ohje on esitetty tässä tutoriaalissa. Bootstrapin versioissa on eroja, ja kannattaakin tarkistaa esim. Collapsible Navbarin toimivuus ensin ilman mitään frontend-kirjastoa esim. tällä tavalla. Kun yksinkertainen esimerkki toimii, sitä voi soveltaa esim. Angularin reititykseen.

Toinen tapa on käyttää valmiita Angular-komponetteja joissa on Bootstrap-tyylit, eli toimitaan samalla tavalla kuin Angular Materialissa. Tämä onnistuu ng-bootstrap -kirjaston avulla. Koko ng-bootsrap -kirjasto, tai vain tarvittavien ngb-komponenttien moduulit importataan app.module.ts:ään käsin, kuten tässä oppaassa on esitetty. Huomaa että ng-bootstrap on täysin oma kirjastonsa, joka sisältää Angular-komponentteja, eikä se ole sama kirjasto kuin tavallinen Bootstrap-peruskirjasto. Et voi siis käyttää tavallisen Bootstrapin ohjeita ng-bootstrapin kanssa.

-Laskin-esimerkki, jossa on käytetty Bootstrapia Angularissa yleisemmällä tavalla eli peruskirjastolla.
-Bootstrapkoe-esimerkki, jossa on tehty collapsible navbar peruskirjastolla pelkkään HTML-tiedostoon, ilman mitään frontend-kirjastoa.

Material Design ja Angular

Angularin MD-komponenttikirjasto on Angular Material. Se asennetaan komennolla ng add @angular/material. MD-komponenttien tyylit tulevat MD-teemasta, joka otetaan käyttöön Angular Materialin asennuksen yhteydessä. Viittaus teemaan syntyy angular.json -tiedostoon. Samalla syntyy pari globaalia tyylisääntöä src/styles.css -tiedostoon.

Sovelluksen käyttöliittymän esittävinä komponentteina käytetään yleensä valmiita MD-käyttöliittymäkomponentteja, jolloin itse tehtyjä komponentteja tarvitaan lähinnä vain MD-komponenttien äitikomponetteina eli "säiliöinä". Jos ei halua käyttää aina valmiita MD-komponentteja, voi MD-tyylejä käyttää myös itse tehdyissä komponenteissa.

Angular Material sisältää valmiiden komponenttien lisäksi Component Dev Kitin eli CDK:n, jonka avulla voi lisätä itse tehtyihin komponentteihin erilaisia käyttöliittymäratkaisuja, kuten esim. Drag and Dropin. CDK antaa vapaammat kädet rakentaa omaperäisiä käyttöliittymäratkaisuja, kuin pelkkä Angular Material.

-Ang-materialdemo -esimerkki, jossa on tehty responsiivinen layout MD-komponenteilla.

4.3.10 Kommunikaatio palvelimen kanssa

Angular-sovellus kommunikoi palvelimen kanssa asynkronisesti HTTP-protokollan yli käyttäen @angular/common/http -moduulin HttpClient-oliota. Kommunikaatio tapahtuu tavallisesti servicen kautta. Service välittää palvelimelta saatavan datan komponenteille ja komponttien lomakkeille syötetyn datan palvelimelle. Komponenttien ja servicen välissä voi olla vielä Store.

Tiedon siirto voi tapahtua HTTP-protokollaan perustuvan REST-APIn välityksellä, GraphQL:llä tai Websocket -protokollalla. HttpClient sisältää XHR-olion, jonka avulla dataa haetaan palvelimelta ja lähetetään palvelimelle. HttpClient palauttaa observablen, josta komponentit saavat datansa tilaamalla sen subscribe-metodilla. HttpClientin ja observablen avulla voidaan välittää komponenttiin sekä yksittäisiä tietoja että reaktiivista tietovirtaa eli streamia.

HttpClient-olion sijasta voidaan käyttää fetch()-metodia, joka palauttaa promisen, mutta fetch ei pysty käsittelemään tietovirtaa eli streamia, vaan ainoastaan yksittäisiä tietoja.

Angularissa voidaan käyttää in-memory-web-apia "valeserverinä", mikäli halutaan kehittää aluksi vain frontendiä, ilman että tarvitsee aloittaa vielä backend -kehitystä. In-memory-web-api otetaan yleensä käyttöön konfiguraatiotiedostossa app.config.ts (esimerkki). Modulaarisissa sovelluksissa käyttöönotto tapahtuu päämoduulissa. In-memory-web-api toimii muistissa aivan kuin oikea serveri, eikä sovelluksen koodia tarvitse muuttaa juuri lainkaan, kun ryhdytään käyttämään oikeaa serveriä. Ainoastaan In-memory-web-apin moduuli pitää ottaa pois käytöstä app.config.ts:stä ja apin url -osoite pitää vaihtaa.

Yksinkertaiset esimerkit kommunikaatiosta palvelimen kanssa:

4.3.11 Testaus

Komponenteille ja muille rakenneosille voidaan suorittaa yksikkötestejä, jotka kirjoitetaan oletuksena Jasmine-kirjaston avulla ja ajetaan Karma test-runnerilla. Nämä testauskirjastot asennetaan automaattisesti Angular CLI:llä luotaviin projekteihin, ellei projektia luotaessa anneta määritystä --minimal . Jos testauskirjastot ovat käytössä, syntyy AngularCLI:llä komponenttia luotaessa yksikkötestin runko komponentin kansioon automaattisesti. Angular-projektissa ei ole enää valmiiksi mukana end-to-end -testauskirjastoa, jollaista käytetään käyttäjän toiminnan simulointiin selaimessa. Se voidaan valita itse tarpeen tai mieltymyksen mukaan.

Kurssilla olemme tarkoituksella jättäneet --minimal -optiolla Angular-projektiin oletuksena tulevat yksikkötestauskirjastot pois. Tämän ansiosta voimme valita itse haluamamme testauskirjastot. Angular-projektiin voidaan asentaa yksikkötestauskirjastoksi esim. Vitest, ja e-to-e -kirjastoksi vaikkapa Cypress.

-Angular-sovellusten testaus

4.3.12 Versiopäivitykset

Angular on nopeasti kehittyvä sovelluskehys ja uusia versioita tulee kuukausittain. Pääasiassa muutokset ovat niin pieniä, että tarvetta sovellusten jatkuvaan päivittämiseen ei ole. Joskus kun sovellusta esimerkiksi jatkokehitetään, tulee tarve siirtyä uusimpaan versioon ja käyttää sen tarjoamia uusia ominaisuuksia. Yksinkertainen tapa tehdä päivitys on uuden projektin luonti uusimmalla Angularin versiolla, ja package.json -tiedoston kirjastojen kopiointi uudesta projektista vanhaan projektiin. Tässä saa tosin olla tarkkana, jotta kaikki kirjastoriippuvuudet tulee uusittua ja ne ovat keskenään yhteensopivia. Angularilla on myös update guide -palvelu joka opastaa päivityksessä.

Koneellesi asennetun globaalin @angular/cli:n päivitys tapahtuu komennoilla:

npm i -g @angular/cli@latest

Annettuasi komennon, on seuraavassa projektissasi käytössä Angularin uusin versio.

4.3.13 Skematiikka ja valmiskomponentit

Sovelluskehittäjän tärkeimpiä sääntöjä on "pyörää ei kannata keksiä uudelleen". Eli Angular-kehityksessäkin kannattaa hyödyntää valmiita komponetteja, moduuleja tai jopa kokonaisia sovelluksia, joita voi käyttää oman sovelluksen osina, tai runkona, jonka päälle oma sovellus voidaan rakentaa. Valmiskomponentit luodaan usein "skematiikan" avulla. Skematiikka eli schematics tarkoittaa komentoja, joilla generoidaan koodia automaattisesti. Komponenttien tai muiden Angular-sovelluksen rakenneosien runkojen luominen Angular-CLI:llä on jo pienimuotoista skematiikkaa. Pidemmälle vietyä skematiikkaa edustaa esim. Material Design -käyttöliittymien ja layoutien rakentaminen komennoilla.

- Angular Material schematics
- Angularin skematiikkaohjeita
- Hyödyllisiä skematiikkakomentoja

Webistä löytyy todella paljon valmiita uudelleenkäytettäviä Angular-rakenneosia, pienistä komponenteista aina suuriin kymmenistä komponenteista muodostuviin modulaarisiin sovelluksiin saakka. Tavanomaisimpia sovelluksia voi toteuttaa erittäin vähäisellä, pienimmillään jopa vain muutaman rivin koodauksella. Paljon käytettyjä suuria valmiskomponentteja, jotka muodostuvat useista alakomponenteista, ovat esim. Ngx-admin, Angular grid - agGrid, Angular datables, Syncfusion Angular scheduler.

- Eniten käytettyjä Angular-valmiskomponenttikirjastoja

***