5: Stemmen

Een peiling zonder stemmen is een lijst. In dit hoofdstuk wordt elke optie een formulier, ontvangt een POST route de stem, gaat de telling omhoog, en een omleiding her-render de pagina. Gewone HTTP, nog geen JavaScript: deze versie werkt in elke browser, met alles uit.

5.1: The vote forms

In poll.phlo, turn each button in the choices view into a tiny form:

view choices:
<section.card>
	<foreach type_poll::records() AS $option>
		<form method=post action="/poll/vote/$option->id">
			<button>$option->option</button>
		</form>
	</foreach>
</section>

Each form posts to its own URL: /poll/vote/1, /poll/vote/2, and so on. The id travels in the path, so the form needs no hidden fields. Note the quotes around the action value: attributes containing variables or slashes must be quoted. The form: display: inline rule from chapter 3 keeps the buttons on one row.

Reload http://localhost/poll: looks identical, but every button now submits a form. Clicking one gives a 404, because the route does not exist yet.

5.2: De POST route

Voeg de route toe aan poll.phlo, nabij de GET-route:

route POST poll vote $id {
	if (!$option = type_poll::record(id: (int)$id)) return false
	type_poll::change('id=?', (int)$id, votes: $option->votes + 1)
	location('/poll')
}

Lees het van boven naar beneden:

Herlaad en klik op Phlo. De pagina herlaadt, de telling leest 1, en de balk springt naar 100%. Klik op een andere optie en kijk hoe de percentages zich herverdelen. Controleer data/poll.json om de stemmen op schijf te zien.

5.3: Een payload in plaats daarvan lezen

De id in het pad is één stijl. De andere is een request body, die je leest via %payload. Schakel eerst de resource in data/app.json in:

{
    "resources": [
        "DB/DB",
        "DB/model",
        "DB/JSONDB",
        "DB/JSON.result",
        "payload"
    ]
}

Een payload-gebaseerde versie van dezelfde route ziet er als volgt uit:

route POST poll vote @option {
	$id = (int)%payload->option
	if (!$option = type_poll::record(id: $id)) return false
	type_poll::change('id=?', $id, votes: $option->votes + 1)
	location('/poll')
}

@option valideert de request body: de payload moet precies de sleutel option bevatten, anders komt de route niet overeen. Body-sleutels worden nooit als parameters gebonden; je leest ze via %payload->option. De bijbehorende vorm zou één formulier zijn met <button name=option value="$option->id"> per keuze.

Beide stijlen zijn idiomatisch. Houd de $id variant uit X.2 voor deze tutorial; het maakt een soepele overgang naar de async versie.

5.4: What you have now

The build keeps itself current on every request; run the checks explicitly if you want the confirmation:

php www/app.php build::run
php www/app.php build::lint

Both settle at []. You have a complete, working poll: server-rendered, refresh-safe, zero JavaScript. Vote a few times, watch data/poll.json change, and notice the one thing that still feels 2004: the full page reload on every vote. That is the next chapter.

We gebruiken essentiële cookies om deze site te laten werken. Met uw toestemming gebruiken we ook analytics om de site te verbeteren.