Ga naar hoofdinhoud

JavaScript erbij

Hier bouw je op verder

Alles wat je tot nu toe hebt gebouwd gaat via de server. Je klikt, de browser vraagt een pagina op, Python stuurt HTML terug, de pagina verspringt. Voor sommige dingen is dat omslachtig — en soms onmogelijk. In deze les zet je JavaScript in je FastAPI-project.

Waar het bestand komt

JavaScript is een gewoon bestand in je static-map, net als je CSS:

je-project/
├── main.py
├── static/
│ ├── css/
│ │ └── style.css
│ └── js/
│ └── app.js
└── templates/

Je hoeft niets aan main.py te veranderen. De regel app.mount("/static", StaticFiles(directory="static"), name="static") uit Static files serveert alles in die map, dus ook je JavaScript.

Koppelen doe je in de <head> van je template:

<script src="/static/js/app.js" defer></script>

Een teller die meteen reageert

Op het gastenboekformulier laat je zien hoeveel tekens er nog over zijn. Voeg een plek toe waar de teller kan staan:

<form method="post" action="/gastenboek">
<input type="text" name="naam" required>
<input type="text" id="bericht-veld" name="bericht" maxlength="80" required>
<p id="teller">80 tekens over</p>
<button type="submit">Verstuur</button>
</form>

En in static/js/app.js:

const veld = document.querySelector("#bericht-veld");
const teller = document.querySelector("#teller");

veld.addEventListener("input", function () {
const over = 80 - veld.value.length;
teller.textContent = over + " tekens over";
});

Bij elke toetsaanslag stuurt de browser een input-event, en jouw functie past de tekst aan.

Kijk wat de server ervan merkt

Typ een paar letters in het veld en kijk dan naar de terminal waar fastapi dev draait.

Daar staat niets nieuws. Geen enkele regel. Je server heeft de teller nooit gezien: het bestand app.js is één keer opgehaald, en daarna doet de browser alles zelf.

Dat is precies het verschil met alles wat je hiervoor bouwde. Een formulier versturen betekent een verzoek naar Python. Een teller bijwerken bij elke toetsaanslag zou dat ook betekenen — twintig verzoeken voor twintig letters, met steeds een halve seconde wachten. Daarom hoort dit in de browser.

Testen

  1. Start je server en ga naar het gastenboekformulier
  2. Typ in het berichtveld en kijk of de teller meeloopt
  3. Kijk in de terminal: er komt geen enkel verzoek bij
Gaat er iets mis?

Doet de teller niets? Druk op F12 en kies het tabblad Console: daar staat elke fout uit je JavaScript in het rood. Staat er Cannot read properties of null, dan vindt je script het element niet. De Console leer je in de volgende les, Console en Elementen, goed kennen. Bekijk de troubleshooting pagina voor meer oplossingen.

Opdrachten

Opdracht 1: Predict - Wat ziet de server?

Je typt het woord "hallo" in het berichtveld, letter voor letter.

Vraag: hoeveel verzoeken ziet je server in de terminal?

Tip

Kijk naar wat er gebeurt bij een toetsaanslag: verandert er iets aan de pagina die de server heeft gestuurd, of vraagt de browser een nieuwe pagina op?

Antwoord

Nul. De pagina en app.js waren al opgehaald voordat je begon te typen. Alle vijf de toetsaanslagen worden afgehandeld door code die al in de browser zit.

Opdracht 2: Run

Maak static/js/app.js, koppel het in je template en voeg het <p id="teller"> toe. Controleer dat de teller meeloopt.

Opdracht 3: Investigate - Defer weghalen

Haal defer weg uit je script-tag, zodat er <script src="/static/js/app.js"></script> staat. Herlaad de pagina en kijk in de console.

Antwoord

Je krijgt TypeError: Cannot read properties of null (reading 'addEventListener').

Zonder defer draait je script meteen, terwijl de browser de <head> leest. De <form> bestaat dan nog niet, dus document.querySelector("#bericht-veld") vindt niets en geeft null terug. Met defer wacht de browser tot de hele pagina er staat.

Opdracht 4: Make - Rood bij bijna vol

Laat de teller rood worden zodra er nog minder dan tien tekens over zijn, en weer zwart als er weer ruimte is.

Tip

teller.style.color = "red" verandert de kleur. Je hebt een if nodig die kijkt of over kleiner is dan tien, met een else voor het andere geval.

Antwoord
const veld = document.querySelector("#bericht-veld");
const teller = document.querySelector("#teller");

veld.addEventListener("input", function () {
const over = 80 - veld.value.length;
teller.textContent = over + " tekens over";

if (over < 10) {
teller.style.color = "red";
} else {
teller.style.color = "black";
}
});

De else is nodig: zonder die regel blijft de teller rood zodra je één keer onder de tien bent geweest, ook als je tekst weer weghaalt.

Opdracht 5: Make - Formulier in- en uitklappen

Zet op je berichtenpagina een knop "Nieuw bericht" die het formulier toont of verbergt. Het formulier begint verborgen.

Tip

Geef het formulier style="display: none" als beginstand. In je JavaScript kun je formulier.style.display op "block" of "none" zetten. Kijk met een if welke van de twee er nu staat.

Antwoord
<button id="klap-knop">Nieuw bericht</button>
<form id="bericht-formulier" method="post" action="/gastenboek" style="display: none">
<input type="text" name="naam" required>
<input type="text" name="bericht" required>
<button type="submit">Verstuur</button>
</form>
const knop = document.querySelector("#klap-knop");
const formulier = document.querySelector("#bericht-formulier");

knop.addEventListener("click", function () {
if (formulier.style.display === "none") {
formulier.style.display = "block";
knop.textContent = "Annuleren";
} else {
formulier.style.display = "none";
knop.textContent = "Nieuw bericht";
}
});

Ook hier komt de server er niet aan te pas. Het formulier stond de hele tijd al in de HTML die Python stuurde; JavaScript laat het alleen zien of verbergt het.