Vuorovaikutteisen toiminnallisuuden lisääminen
Learning objectives
- Tutustut käsitteisiin tapahtuma, tapahtumankäsittelijä ja tapahtumaohjattu ohjelmointi.
- Osaat lisätä, poistaa ja muokata HTML-dokumentin elementtejä ohjelmallisesti.
- Osaat lisätä HTML-dokumenttien elementteihin vuorovaikutteista toiminnallisuutta.
Tutustutaan seuraavaksi vuorovaikutteisen toiminnallisuuden lisäämiseen verkkosivuille. Käytämme vuorovaikutteisen toiminnallisuuden toteuttamiseen Johdatus ohjelmointiin ja Data ja tieto -kursseilla käytettyä Dart-ohjelmointikieltä.
Johdatus HTML:n ja Dartin vuorovaikutukseen
Tutustutaan seuraavaksi HTML-dokumenttien ja Dart-kielisten ohjelmien yhdistämiseen. Luomme tällaisissa ohjelmissa HTML-dokumentin ja Dart-ohjelman erillisinä osina, jotka sijaitsevat ohjelmointiympäristön eri välilehdillä. Dart-kielinen ohjelma sijaitsee välilehdellä Dart ja HTML-dokumentti välilehdellä HTML.
Kun ohjelma suoritetaan, Dart-kielinen ohjelma käännetään JavaScript-kieliseksi ohjelmaksi, joka yhdistetään HTML-sivuun. Kun sivu avataan selaimessa, selain suorittaa sivuun liittyvän JavaScript-koodin.
Vuorovaikutteisen sisällön luominen tapahtuu käytännössä siten, että ohjelmakoodi "liitetään" sivuun. Kun käyttäjä avaa sivun tai on vuorovaikutuksessa sivulla olevien elementtien kanssa, sivuun liitetty ohjelmakoodi suoritetaan.
HTML-elementtien tunnistaminen
Ohjelmakoodin liittäminen sivun elementteihin vaatii elementtien tunnistamisen. HTML-elementeille voidaan määritellä elementin yksilöivä attribuutti id
, jonka arvoksi asetetaan tunniste, johon voidaan myöhemmin viitata.
Alla olevassa esimerkissä tekstielementille p
on määritelty id
-attribuutti, jonka arvo on teksti
. Tässä tekstielementti yksilöidään merkkijonon teksti
perusteella.
<p id='teksti'>Hei kaikki!</p>
HTML-elementtien hakeminen ohjelmassa tapahtuu querySelector
-funktion avulla. Funktio on osa dart:html
-kirjastoa. Funktiolle annetaan merkkijonomuotoisena parametrina haku, ja se palauttaa ensimmäisen hakua vastaavan HTML-elementin.
Haku id
-attribuutin arvon perusteella tapahtuu asettamalla hakua kuvaavan merkkijonon alkuun risuaita #
, jota seuraa haettavan elementin id
-attribuutin arvo. Esimerkiksi kutsu querySelector('#nappi')
hakee elementtiä, jonka id
-attribuutin arvo on nappi
.
Alla olevassa esimerkissä on ohjelma, joka hakee HTML-dokumentista elementin, jonka id
-attribuutin arvo on teksti
. Haetulla elementillä ei vielä tehdä mitään.
import 'dart:html';
main() {
var elementti = querySelector('#teksti');
}
Funktio querySelector
palauttaa HTMLElement-olion. Tässä kohtaa on hyvä tiedostaa, että Dart-kielen dokumentaatiosta löytyy tiedot käsittelemistämme elementeistä. Pääset dokumentaatioon edellistä linkkiä klikkaamalla.
Jokaisella HTMLElement
-luokasta tehdyllä oliolla on attribuutti text
, jonka arvon voi asettaa ohjelmallisesti. Alla olevassa esimerkissä id
-attribuutin arvolla teksti
tunnistettavan elementin text
-attribuutin arvoksi asetetaan Minä muutuin!
.
import 'dart:html';
main() {
var elementti = querySelector('#teksti');
elementti.text = 'Minä muutuin!';
}
Kun selaimella ladataan sivu, joka sisältää teksti
-id:llä yksilöidyn elementin sekä yllä olevasta Dart-kielisestä ohjelmasta käännetyn JavaScript-ohjelman, käyttäjä näkee sivulla tekstin Minä muutuin!
.
Alla ohjelmointiympäristöön on toteutettu luvun arpova ohjelma. Kun käyttäjä avaa sivun, hän näkee satunnaisesti yhden ja viiden väliltä valitun luvun. Satunnaisesti valittu luku näkyy sivulla tekstin "Tähän tulee luku!" sijaan.
Tapahtumat selaimessa
Käyttäjän ja sivujen vuorovaikutus kuten vaikkapa tekstin tai napin painaminen aiheuttavat tapahtumia. Selain käsittelee tapahtumat selainsovellukseen toteutetulla tavalla. Voimme kuunnella sivulla tapahtuvia tapahtumia ja lisätä sivulle ohjelmakoodia, joka suoritetaan tapahtuman yhteydessä. Esimerkiksi kurssin Data ja tieto johdannossa on tekstielementti, jota klikkaamalla tekstin merkkien järjestys muuttuu satunnaiseksi.
Tutustutaan ensin klikkaustapahtumaan ja sen käsittelyyn. Kullakin elementillä on attribuutti onClick
, johon liittyy metodi listen
. Metodin listen
avulla kerrotaan mitä elementtiin liittyvän klikkaustapahtuman yhteydessä tulee tehdä. Metodi listen
saa parametrinaan tapahtuman käsittelyyn tarkoitetun funktion, jonka ohjelmakoodi suoritetaan klikkaustapahtuman yhteydessä.
Tapahtuman käsittelyyn tarkoitettu funktio saa parametrinaan Event
-tyyppisen olion, joka kuvastaa tapahtumaa. Tällainen funktio määritellään seuraavalla tavalla.
kasittele(Event e) {
print('Jotain tapahtui!');
}
Yllä oleva funktio tulostaa viestin Jotain tapahtui!
. Funktion parametrin tyyppi Event
on määritelty yllä eksplisiittisesti, mutta funktion voi kirjoittaa myös ilman eksplisiittistä parametrin tyyppiä kuten alla.
kasittele(e) {
print('Jotain tapahtui!');
}
Funktion antaminen parametrina listen
-metodille on suoraviivaista: metodi saa parametrinaan funktion nimen. Alla olevassa esimerkissä id
-attribuutin arvolla teksti
tunnistetulle elementille lisätään klikkaustapahtumien käsittelijä. Kun elementtiä klikataan, ohjelma tulostaa viestin Jotain tapahtui!
.
import 'dart:html';
main() {
var elementti = querySelector('#teksti');
elementti.onClick.listen(kasittele);
}
kasittele(e) {
print('Jotain tapahtui!');
}
Funktion print
tulostama teksti lisätään konsoliin. Ohjelmointiympäristössämme konsoli löytyy vasemmalla näkyvän ohjelmakoodialueen alapuolelta. Klikkaamalla konsolin auki näet sinne tulostuvat tekstit. Voit kokeilla yllä olevaa ohjelmaa sekä konsoliin tapahtuvaa tulostusta alla olevassa ohjelmointiympäristössä.
Tapahtumien käsittely
Tapahtumien käsittelyyn tarkoitetut funktiot ovat funktioita siinä missä muutkin funktiot. Tämä tarkoittaa sitä, että tapahtumien yhteydessä voidaan tehdä mitä tahansa mitä ohjelmoija keksii toteuttaa.
Tyypillisesti tapahtumien käsittely liittyy jollain tavalla elementtiin, jonka kanssa käyttäjä on vuorovaikutuksessa (tai sen lähellä oleviin elementteihin).
Alla olevassa esimerkissä on nappi ja tekstielementti. Tekstielementissä on nolla. Nappiin liittyvää klikkaustapahtumaa kuuntelee kasittele
-funktio. Kun nappia painetaan, funktio kasittele
suoritetaan. Funktio kasvattaa tekstikentässä olevaa arvoa yhdellä.
Useampi elementti ja tapahtumankäsittelijä
Sama funktio voidaan asettaa kuuntelemaan useammassa elementissä tapahtuvia tapahtumia. Alla olevassa esimerkissä on kolme nappia ja tekstielementti. Kunkin napin painaminen kasvattaa tekstielementissä olevaa lukua yhdellä.
Ohjelmassa voi olla myös useampia tapahtuman käsittelyyn tarkoitettuja funktioita. Alla olevassa esimerkissä on kaksi nappia ja tekstielementti. Tekstielementissä on nolla, yhdessä napeista on plusmerkki ja toisessa miinusmerkki.
Jos käyttäjä painaa plusmerkin sisältävää nappia, tekstielementissä oleva luku kasvaa yhdellä. Jos taas käyttäjä painaa miinusmerkin sisältävää nappia, tekstielementissä oleva luku pienenee yhdellä.
Yllä olevassa ohjelmointiympäristössä olevan ohjelman funktiot kasvata
ja pienenna
ovat hyvin samankaltaisia. Luodaan apufunktio, jonka vastuulle pääosa työstä siirretään -- tämä voi selkeyttää ohjelman lähdekoodia.
Alla olevassa esimerkissa funktiot kasvata
ja pienenna
kutsuvat apufunktiota muuta
. Funktio muuta
muuttaa tekstielementissä olevaa luvun arvoa parametrina annetun luvun perusteella.
import 'dart:html';
main() {
querySelector('#plus').onClick.listen(kasvata);
querySelector('#miinus').onClick.listen(pienenna);
}
kasvata(e) {
muuta(1);
}
pienenna(e) {
muuta(-1);
}
muuta(muutos) {
var elementti = querySelector('#luku');
var luku = int.parse(elementti.text);
luku = luku - muutos;
elementti.text = '$luku';
}
Erilaisia elementtejä ja tekstikentän käsittely
Tarkastellaan seuraavaksi tekstikentän tapahtumien käsittelyä ohjelmallisesti. Luodaan ohjelma, missä käyttäjää pyydetään syöttämään nimi ja painamaan nappia. Tämän jälkeen ohjelmassa näytetään viesti "Hei nimi, hauska tutustua!".
Ohjelman HTML-dokumentissa tulee olla tekstin syöttämiseen tarkoitettu input
-elementti, nappi, sekä tervehdyksen näyttämiseen tarkoitettu tekstielementti. Oleellisilta osin dokumentti näyttää seuraavalta.
<input type='text' id='syote'></input>
<button id='nappi'>Paina tästä!</button>
<p id='teksti'></p>
Luodaan seuraavaksi ohjelma, joka reagoi napin painallukseen ja luo käyttäjälle näytettävän tervehdyksen.
Ohjelmassa lisätään napin klikkaustapahtumaa kuunteleva funktio. Funktio hakee tekstin syöttämiseen tarkoitetusta input
-elementistä sen arvon ja käyttää sitä osana tervehdystä. Tervehdys asetetaan tekstielementin tekstiksi.
import 'dart:html';
main() {
querySelector('#nappi').onClick.listen(tervehdi);
}
tervehdi(e) {
var syote = querySelector('#syote').text;
var teksti = 'Hei $syote, hauska tutustua!';
querySelector('#teksti').text = teksti;
}
Ohjelma ei kuitenkaan toimi halutulla tavalla. Kun käynnistämme ohjelman ohjelmointiympäristössä ja painamme nappia, näemme tekstin "Hei , hauska tutustua!". Käyttäjän tekstikenttään syöttämää arvoa ei näy missään!
Ongelmassa on kyse siitä, että kaikkien elementtien arvo ei löydy text
-attribuutista: tekstikentän arvo on attribuutissa nimeltä value
. Muutetaan ohjelmaa hieman ja otetaan syote talteen attribuutista value
.
import 'dart:html';
main() {
querySelector('#nappi').onClick.listen(tervehdi);
}
tervehdi(e) {
var syote = querySelector('#syote').value;
var teksti = 'Hei $syote, hauska tutustua!';
querySelector('#teksti').text = teksti;
}
Ohjelma ei vieläkään toimi. Näemme virheen The getter 'value' isn't defined for the type 'Element' - line 8
. Virhe kertoo, että querySelector
-funktion tunnistamassa elementissä ei ole value
-nimistä muuttujaa.
Tässä on kyse siitä, että querySelector
-funktion toteuttajalla ei ole ollut tiedossa, minkälaisia elementtejä funktio löytää. Funktio on luotu niin, että se palauttaa "tyypillisen" elementin, jossa on yleisiä attribuutteja sekä elementtiin liittyvien tapahtumien käsittelyyn tarkoitettuja ominaisuuksia.
Tekstikenttää vastaa tekstin syöttämiseen tarkoitettu InputElement
-luokka. Muokataan ohjelmaa siten, että määrittelemme querySelector
-funktion palauttaman elementin tyypin.
import 'dart:html';
main() {
querySelector('#nappi').onClick.listen(tervehdi);
}
tervehdi(e) {
InputElement tekstikentta = querySelector('#syote');
var syote = tekstikentta.value;
var teksti = 'Hei $syote, hauska tutustua!';
querySelector('#teksti').text = teksti;
}
Määrittelemällä querySelector
-funktion palauttaman olion tyypin tekstikentäksi ohjelma "tietää" mistä elementistä on kyse. Nyt attribuutti value
löytyy ja sitä voi käyttää osana ohjelmaa.
Muutostapahtumien käsittely
Edellisissä esimerkeissä käsiteltiin klikkaustapahtumaa onClick
. Tutustutaan seuraavaksi muutostapahtumiin eli esimerkiksi tekstikentän arvon vaihtumiseen.
Toteutamme tässä ensiaskeleet lahjaveron laskemiseen tarkoitettuun ohjelmaan.
Luodaan ensin HTML-dokumentti, joka sisältää ohjetekstin, lahjan arvon syöttämiseen tarkoitetun kentän, ja lasketun lahjaveron näyttämiseen tarkoitetun taulukon.
<p>Syötä lahjan määrä</p>
<input type='number' id='summa'></input>
<table>
<tr>
<td>Veroihin</td>
<td>Lahjaksi</td>
</tr>
<tr>
<td id='vero'></td>
<td id='lahja'></td>
</tr>
</table>
Dokumentti näyttää selaimessa seuraavalta.
Aloitetaan veron laskemiseen tarkoitetun toiminnallisuuden toteuttaminen. Lisätään ohjelmaan ensin tekstikenttään tehtyjä muutoksia kuunteleva funktio. Muutostapahtumien kuuntelu tapahtuu onChange
-attribuutin kautta.
import 'dart:html';
main() {
querySelector('#summa').onChange.listen(paivita);
}
Luodaan seuraavaksi funktio paivita
, joka käsittelee muutostapahtumat. Funktio lukee tekstikentästä arvon, muuntaa sen luvuksi, laskee luvun perusteella veron ja lahjan määrän, ja asettaa nämä taulukkoon näkyville.
Alla veron ja lahjan laskemiseen tarkoitetut funktiot eivät sisällä oikeaa toiminnallisuutta. Niitä voi kuitenkin käyttää ohjelman toiminnan kokeilemiseen.
paivita(e) {
InputElement syote = querySelector('#summa');
var summaTekstina = syote.value;
int summa = int.parse(summaTekstina);
var v = vero(summa);
var l = lahja(summa);
querySelector('#vero').text = '$v';
querySelector('#lahja').text = '$l';
}
vero(summa) {
return 10;
}
lahja(summa) {
return summa - vero(summa);
}
Noudatamme ohjelmassa vuonna 2017 tai sen jälkeen lähisukulaiselta saadun lahjan laskemiseen tarkoitettua taulukkoa (lähde vero.fi). Alla on osa taulukosta.
Lahjan arvo (euroa) | Vero alarajan kohdalla (euroa) | Veroprosentti ylimenevästä osasta (%) |
---|---|---|
5 000 - 25 000 | 100 | 8 % |
25 000 - 55 000 | 1700 | 10 % |
55 000 - 200 000 | 4700 | 12 % |
200 000 - 1 000 000 | 22 100 | 15 % |
... | ... | ... |
Aloitetaan funktion vero
kehittäminen. Alle 5000 euron lahjasta veroa ei makseta.
vero(summa) {
if (summa < 5000) {
return 0;
}
return 10;
}
Mikäli summa on suurempi tai yhtä suuri kuin 5000 euroa, mutta pienempi kuin 25000 euroa, on vero alarajan kohdalla 100 euroa. Tämän lisäksi ylimenevästä osasta maksetaan 8% veroa. Lisätään tämä funktioon vero
.
vero(summa) {
if (summa < 5000) {
return 0;
}
if (summa < 25000) {
return 100 + (summa - 5000) * 0.08;
}
return 10;
}
Kun kokeilemme ohjelmaa, huomaamme, että lahjasta maksettava veron määrä näytetään vasta kun käyttäjä siirtää fokuksen pois lahjan määrän syöttämiseen tarkoitetusta elementistä (eli esimerkiksi klikkaa muualla dokumentissa).
Mikäli haluamme, että veron määrä päivitetään jokaisen näppäinpainalluksen jälkeen, tulee kuunneltavaksi tapahtumaksi asettaa onKeyUp
-tapahtuma. Tällöin tapahtumaa kuuntelevaa funktiota kutsutaan jokaisen tekstielementtiin liittyvän näppäinpainalluksen jälkeen eli aina kun joku näppäimistön näppäin nousee ylös.
main() {
querySelector('#summa').onKeyUp.listen(paivita);
}
Tekstikenttien automaattinen täydennys
Selaimet tarjoavat toiminnallisuuden tekstikenttien automaattiseen täydennykseen. Tämä helpottaa usein toistuvien syötteiden lisäämistä. Kaikissa ohjelmissa kyseinen toiminnallisuus ei kuitenkaan ole toivottua. Mikäli automaattisen täydennyksen haluaa pois päältä, voi tekstielementtiin lisätä attribuutin autocomplete
, jonka arvona on off
.
<input type='text' autocomplete='off'></input>
HTML-elementtien lisääminen
Toistaiseksi esimerkkimme ovat käsitelleet olemassaolevien elementtien muokkaamista. Tarkastellaan seuraavaksi uusien elementtien lisäämistä ohjelmiin.
Dartin tarjoama Element-luokka sisältää joukon konstruktoreja (eli olion luomiseen tarkoitettuja funktioita), joiden avulla voidaan luoda uusia HTML-elementtejä. Alla olevassa esimerkissä HTML-dokumenttiin on määritelty div
-elementin avulla alue, joka voidaan tunnistaa sen id
-attribuutin arvon perusteella.
<div id='alue'></div>
Seuraavassa ohjelmassa luodaan uusi tekstielementti konstruktorikutsulla Element.p()
, jonka jälkeen tekstielementtiin asetetaan teksti Hei maailma!
. Tämän jälkeen elementti lisätään div
-elementin sisälle elementin lapseksi.
import 'dart:html';
main() {
var teksti = Element.p();
teksti.text = 'Hei maailma!';
querySelector('#alue').children.add(teksti);
}
Kun ohjelma on suoritettu, HTML-dokumentti näyttää seuraavalta. Alla olevaan kuvaukseen on lisätty myös HTML-dokumentin juuri ja otsake (head). Otsake on jätetty tyhjäksi.
Mikäli ohjelmassa lisätään kaksi p
-elementtiä div
-elementin sisään (eli lisätään div
-elementille kaksi lasta), näyttää dokumentti seuraavalta.
Luokkaan Element liittyvän dokumentaation oikeassa laidassa näkyy lista luokan tarjoamista konstruktoreista. Luokan avulla voidaan luoda useita erilaisia elementtejä -- se tarjoaa muunmuassa listojen luomiseen tarkoitetut konstruktorit Element.ol()
, Element.ul()
ja Element.li()
.
Alla olevassa esimerkissä luodaan ensin järjestämätön lista, jonka jälkeen listalle lisätään kaksi listaelementtiä. Esimerkissä oletetaan, että käytössä on elementti, jonka id
-attribuutin arvo on alue
.
import 'dart:html';
main() {
var lista = Element.ul();
var ensimmainen = Element.li();
ensimmainen.text = 'eka';
lista.children.add(ensimmainen);
var toinen = Element.li();
toinen.text = 'toka';
lista.children.add(toinen);
querySelector('#alue').children.add(lista);
}
Lopputuloksena on sivu, joka sisältää listan. Listalla on kaksi arvoa. Näistä ensimmäisessä on teksti "eka" ja toisessa teksti "toka".
Elementtien lisääminen voidaan lisätä myös tapahtumien käsittelyn yhteyteen. Alla olevassa ohjelmointiympäristössä on ohjelma, joka lisää listaan uuden arvon käyttäjän painaessa "Lisää!"-nappia.
Luotaville elementeille voi lisätä myös tapahtumankuuntelijoita, täysin samalla tavalla kuin sivulla jo oleville elementeille.
Alla olevassa esimerkissä listalle lisättävään elementtiin lisätään tapahtumankuuntelija. Kun käyttäjä klikkaa listaelementtiä, konsoliin tulostetaan viesti "Jotain tapahtui!".
import 'dart:html';
main() {
querySelector('#nappi').onClick.listen(lisaa);
}
lisaa(e) {
var elementti = Element.li();
elementti.text = 'Hei!';
elementti.onClick.listen(tapahtuma);
querySelector('#lista').children.add(elementti);
}
tapahtuma(e) {
print('Jotain tapahtui!');
}
HTML-elementtien poistaminen
Yksittäisten elementtien poistaminen onnistuu elementtiin liittyvällä remove
-metodilla.
Alla olevassa esimerkissä on HTML-dokumentti, jossa on tekstielementti. Ohjelmassa tekstielementtiin on liitetty tapahtumaa kuunteleva funktio. Kun tekstielementtiä klikataan, se poistetaan.
Tapahtuman käsittelyyn tarkoitetun funktion voi määritellä myös suoraan listen
-metodille. Alla olevassa esimerkissä poistamiseen tarkoitettu funktio on toteutettu listen
-metodin yhteyteen.
import 'dart:html';
main() {
querySelector('#teksti').onClick.listen((e) {
querySelector('#teksti').remove();
});
}
Yllä luodaan niinsanottu anonyymi funktio eli funktio, jolle ei ole annettu nimeä. Funktioon määritelty lähdekoodi suoritetaan tekstielementin klikkauksen yhteydessä.
Luotujen elementtien poistaminen onnistuu vastaavasti anonyymien funktioiden avulla. Alla olevassa esimerkissä luodaan uusi listalle lisättävä elementti. Elementtiin liittyviä klikkaustapahtumia asetetaan kuuntelemaan anonyymi funktio. Funktiota kutsuttaessa juuri luotu elementti poistetaan.
import 'dart:html';
main() {
querySelector('#nappi').onClick.listen(lisaa);
}
lisaa(e) {
var elementti = Element.li();
elementti.text = 'Hei!';
elementti.onClick.listen((e) {
elementti.remove();
});
querySelector('#lista').children.add(elementti);
}
Tapahtumaohjattu ohjelmointi
Täss ä osassa on käsitelty tapahtumaohjattua ohjelmointia. Tapahtumaohjatussa ohjelmoinnissa kyse on ohjelmointityylistä, missä ohjelmakoodia suoritetaan tapahtumakohtaisesti. Tällainen tyyli on hyvin tyypillistä esimerkiksi graafisia käyttöliittymiä ja verkkosivuja luotaessa.
Selainohjelmissa tapahtumien käsittelyssä ovat vuorovaikutuksessa (1) käyttöjärjestelmä, joka mahdollistaa muunmuassa hiiren käytön sekä selaimen käynnistymisen, (2) selain, joka näyttää sivuja ja tulkitsee niissä olevaa lähdekoodia, ja (3) sivu, jolle on määritelty sekä sisältö että mahdollinen toiminnallisuus. Painikkeen painamiseen liittyvän tapahtuman käsittelyyn liittyy monta askelta.
Tapahtumaohjatun ohjelmoinnin keskiössä ovat tapahtumat ja niiden käsittelyyn tarkoitetut funktiot. Aiemmissa esimerkeissä oioimme tarkoituksella hieman emmekä käsitelleet käyttöjärjestelmän tai selaimen konkreettista roolia. Kun lisäämme tapahtuman käsittelyyn tarkoitetun funktion tapahtumaan liittyvän listen
-metodin avulla, lisäämme (tai "rekisteröimme") funktion elementtiin liittyvälle tapahtumankäsittelijälle.
Alla tämä toiminnallisuuden lisääminen tapahtumankäsittelijälle on esitetty pseudokoodina, eli käyttämäämme lähdekoodia muistuttavana koodina.
Kun käyttäjä klikkaa selaimessa nappia tai tekee jonkun muun toiminnon, toiminnosta siirtyy käyttöjärjestelmältä tieto selaimelle, josta se siirtyy tapahtumankäsittelijälle. Tapahtumankäsittelijä käsittelee tapahtuman ja kutsuu jokaista elementtiin liittyvään tapahtumankäsittelijään lisättyä funktiota.
Hi! Please help us improve the course!
Please consider the following statements and questions regarding this part of the course. We use your answers for improving the course.
I can see how the assignments and materials fit in with what I am supposed to learn.
I find most of what I learned so far interesting.
I am certain that I can learn the taught skills and knowledge.
I find that I would benefit from having explicit deadlines.
I feel overwhelmed by the amount of work.
I try out the examples outlined in the materials.
I feel that the assignments are too difficult.
I feel that I've been systematic and organized in my studying.
How many hours (estimated with a precision of half an hour) did you spend reading the material and completing the assignments for this part? (use a dot as the decimal separator, e.g 8.5)
How would you improve the material or assignments?