Tijdschrift voor webwerkers » Artikel #101
Bij het invullen van een formulier op een website kan een hoop mis gaan. Op zo’n moment kunnen we natuurlijk denken dat de bezoeker een beetje dom is. Maar we kunnen er ook voor zorgen dat die bezoeker zo snel mogelijk en op juiste wijze het formulier kan verzenden. Want frustratie kost geld, en iemand helpen kan geld opleveren.
Onze fictieve opdrachtgever wil graag de bezoekers van haar site de mogelijkheid geven om een brochure aan te vragen. Deze brochure is de eerste kennismaking met het bedrijf, dus gaat onze opdrachtgever de aanstaande klant niet het hemd van het lijf vragen. Dat is slim, want veel bedrijven trappen in de valkuil om de bezoeker eerst een compleet curriculum vitae in te laten vullen voordat ze iets simpels als een brochure kunnen aanvragen.
Het bedrijf van onze opdrachtgever beschikt over een database waarin de postcodes van Nederland zijn opgeslagen. Daar gaan we natuurlijk gebruik van maken. Om een formulier te controleren voordat het uiteindelijk verwerkt kan worden zijn verschillende technieken bruikbaar (Perl, JavaScript, PHP, etc.). De ene techniek is niet per definitie beter dan de ander, maar in ons voorbeeld kiezen we voor PHP. Alle invoervelden zijn verplicht in het voorbeeld.
Voorbeeld:
Onze opdrachtgever wil zo veel mogelijk brochures verspreiden en – zoals gezegd – ze is slim. Aan belangstellenden stuurt ze één keer een brochure, maar ze weet ook wel dat die net op een moment kan komen dat de potentiële klant geen acute behoefte heeft aan haar product. Daarom stuurt ze op een later moment nogmaals een brochure, iets wat ze ook eerlijk vertelt als de potentiële klant zich aanmeldt.
Onze opdrachtgever wil geen uitgebreid adressenbestand van mensen die ooit een brochure hebben aangevraagd. Ze wil wel een goed adressenbestand opbouwen – van mensen die klant geworden zijn.
Het is te allen tijde raadzaam om een een “privacy statement” aan je formulier toe te voegen. Zo’n statement schept vertrouwen in de organisatie achter de website. En omdat mensen precies weten wat je met hun gegevens gaat doen, zijn ze sneller bereid om de gegevens te verstrekken.
Nu kunnen we een heel leger advocaten op een privacy statement afsturen. Zij zullen zo’n statement goed, nauwkeurig en volgens de regels dichttimmeren. Soms kan dat nodig zijn. In ons geval lijkt een batterij advocaten een beetje te veel van het goede, dus formuleren we het kort, bondig en in “normalemensentaal”.
Ons voorbeeld:
Wij gebruiken de verstrekte gegevens alleen voor het toesturen van de aangevraagde brochure en één vervolgbrochure.
Dit lijkt al aardig op een formulier waar niks mis mee is. Maar je kunt op je klompen aanvoelen dat dat dan ook het einde zou zijn van dit artikel. Dat is het niet: we realiseren ons namelijk dat er ook wel iets mis zou kunnen gaan bij het invullen en versturen. En het leukste is... alles wat je kunt bedenken dat fout zou kunnen gaan, gaat een keer fout. Alles wat je niet had bedacht trouwens ook.
De vereisten voor dit formulier zijn dat de foutmelding wordt gegeven bij het veld (of meerdere velden) waar het mis is gegaan. De oplossing moet bovendien voldoen aan toegankelijkheidseisen: ook iemand die gebruik maakt van een screen reader moet weten wat er mis is gegaan. En de melding moet zowel hulpvaardig zijn als voldoende in het oog springen.
Het formulier zullen we opnemen in een PHP-pagina die een postback doet naar zichzelf. Op die manier kunnen we de foutmeldingen makkelijk toevoegen, zonder terug te moeten vallen op client-side JavaScript oplossingen. Op die laatste kunnen we namelijk niet blind vertrouwen: we weten immers niet of de bezoeker van de website JavaScript heeft ingeschakeld.
In plaats van een specifieke oplossing voor dit ene probleem te verzinnen, kiezen we voor het opzetten van een raamwerk. Dit generieke raamwerk kan later makkelijk hergebruikt worden voor andere formulieren, wat ons tijd en ontwikkelingskosten bespaart.
Ons raamwerk maakt gebruik van de object-gerichte technieken die door PHP aangeboden worden. We werken met drie types objecten:
Check
objecten beschrijft welke testen moet uitgevoerd worden op welke velden. Zo gaat een NonEmptyCheck
na of een veld al dan niet leeg is, terwijl een PostCodeCheck
de geldigheid van een postnummer nagaat.Action
object stelt de actie voor die genomen moet worden wanneer alle velden in het formulier correct zijn ingevuld. In ons geval is dit het toevoegen van het adres aan het adressenbestand, wat we zullen doen via een RegisterClientAction
.Verify
object combineert een stel Check
s met een Action
.De exacte implementatie tonen we hier niet, maar je vindt de volledige code hier: verify.inc.php.
Allereerst voegen we helemaal bovenaan de pagina waar het formulier in staat het volgende stuk code in. Hierin wordt gedefinieerd welke testen we op het formulier willen uitvoeren.
<?php
// form verification
require('verify.inc.php');
class RegisterClientAction extends Action
{
function doAction(&$aVars)
{
// plaats data in databank
// ...
// stuur bezoeker naar een bedank-pagina
header('Location: bedankt.html');
exit();
}
}
$verify = new Verify(array(
'verify-brochure' => array(
// testen die uitgevoerd moeten worden
'checks' => array(
'naam' => new NonEmptyCheck('U dient uw naam in te vullen.'),
'postcode' => new PostCodeCheck('Postcode onjuist.',
'Postcode bestaat niet.'),
'huisnummer' => new HuisNummerCheck('Huisnummer missing.',
'No match. ')
),
// actie om achteraf uit te voeren
'action' => new RegisterClientAction(),
// manier om foute velden aan te geven
'errorIndication' => '<img src="fout_ikoon.gif" width="11" height="11" alt="Let op!" /> '
)
));
?>
De RegisterClientAction
klasse zal gebruikt worden om het adres aan het adressenbestand toe te voegen, en om de bezoeker door te sturen naar een bedank-pagina. De doAction
method zal (wanneer nodig) door Verify
aangeroepen worden.
$verify
wordt een object van het Verify
type. De data die aan de constructor meegegeven wordt, vertelt dat er zich een verify-brochure
-formulier op de pagina bevindt en dat hiervoor de volgende karakteristieken gelden:
RegisterClientAction
uitgevoerd wordenHet aanmaken van een Verify
zet een heel raderwerk in beweging. Als de pagina opgevraagd wordt als gevolg van versturen van het formulier, tenminste. In dat geval wordt volgend lijstje doorlopen:
Zoals we eerder eisten, willen we de foutmeldingen bij het formulier zelf plaatsen. Daarnaast zou het ook handig zijn als de velden van het formulier alvast werden ingevuld. Hiervoor moeten we wat extra PHP-suiker aan de HTML code van het formulier toevoegen.
Allereerst voegen we een identificatie van het formulier toe. Op die manier kunnen we eventueel meerdere formulieren op een zelfde pagina van elkaar onderscheiden. De identificatie (verify-brochure
) voegen we toe als een verborgen veld, en is dezelfde als wat we bij het creëren van het Verify
object gebruikten. Daarnaast zorgen we ervoor dat het formulier naar onszelf gezonden wordt, door het action
attribuut van het form
element aan te passen. We voegen ook een bestelBrochure
anker toe, zodat de browser direct terugspringt naar het formulier indien er iets foutloopt. Dit laatste is handig als je formulier in het midden van een lange pagina staat. Samen geeft dit:
<h2 id="bestelBrochure">Bestel onze brochure</h2>
<form action="#bestelBrochure" method="post">
<input type="hidden" name="verify" id="verify" value="verify-brochure" />
...
</form>
Voor elk veld in het formulier voegen we nu wat PHP-code toe. Deze zal een uitroepteken toevoegen vóór het label, de vorige waarde opnieuw invullen en class="error"
toevoegen aan zowel het input
als het label
element. Daarnaast worden zowel het label
als input
element in een strong
element ingesloten, waardoor ook met screenreaders rekening gehouden wordt.
De aanpassing voor het naam-veld is hieronder gegeven. De aanpassingen aan andere velden zijn gelijkaardig.
<?php $verify->onError('verify-brochure', 'naam', '<strong>');?>
<label for="naam"
class="<?php $verify->errorClass('verify-brochure', 'naam');?>"
><?php $verify->errorIndication('verify-brochure', 'naam');?>Naam</label>
<input type="text" name="naam" id="naam"
value="<?php $verify->insertVar('verify-brochure', 'naam');?>"
class="<?php $verify->errorClass('verify-brochure', 'naam');?>" />
<?php $verify->onError('verify-brochure', 'naam', '</strong>');?>
De CSS-klasse error
kan gebruikt worden om visueel weer te geven dat er iets fout is. Een gele achtergrond voor de invoervelden en vette rode tekst voor de labels: zo zorgen we er voor dat de bezoeker die gefocust is op de invulvelden weet waar het mis is gegaan:
input.error {
background-color: yellow;
}
label.error {
font-weight: bold;
color: red;
}
Als laatste voegen we onderaan het formulier nog een samenvatting van alle fouten in. De foutmeldingen worden zo aan elkaar geplakt dat ze een nette unordered list vormen.
<?php
$verify->errorSummary(
'verify-brochure',
'<ul class="error"><li>', // start
'</li><li>', // tussen foutmeldingen
'</ul>' // eind
);
?>
Waarom zetten we de lijst met fouten nou onderaan het formulier en niet bovenaan? Voor beide posities valt iets te zeggen, maar we kiezen hier voor onderaan, zo dicht mogelijk bij de ‘verstuur’-knop. Het oog van de bezoeker is namelijk gericht op deze knop, de laatste die hij heeft ingedrukt. Als je de foutmelding in de buurt van de plaats van de laatste actie toont, is de kans zo groot mogelijk dat de melding gezien wordt. In het hoofd van de bezoeker zou het als volgt kunnen gaan: ‘Hé, ik heb op de knop gedrukt maar ik krijg nogsteeds het formulier te zien. Heb ik niet goed op de knop gedrukt? O, kijk, er staat opeens een rode tekst bij, daar moet ik vast iets mee doen...’
Het formulier werkt nu goed en is voorbereid op alle eventualiteiten. Technisch is dus alles OK. Maar op het menselijk vlak kan er nog wel iets verbeteren: onze programmeur heeft niet echt gedacht aan de begrijpelijkheid en de toon van de foutmeldingen. Wat moet een bezoeker bijvoorbeeld met de melding ‘no match’? Zo weet de bezoeker niet wat er mis is gegaan, wat hij er aan kan doen om de fout te verhelpen en de toon is ook op z’n minst kil te noemen. Daar moeten we dus nog even aan werken.
We beginnen met ‘U dient uw naam in te vullen.’ ‘Dient’ heeft een nare, dwingende ondertoon. We kunnen dat beter wat vriendelijker brengen: ‘Wilt u uw naam invullen?’
Dan ‘Postcode onjuist.’ Dat is natuurlijk een heldere mededeling, maar je kunt je postcode op heel veel manieren verkeerd invullen. Onze programmeur is gelukkig zo slim geweest om de instellingen zó te zetten dat het niet uitmaakt of je een spatie invult of niet en of je hoofdletters of kleine letters gebruikt. Maar er zijn nog andere dingen die mis kunnen gaan: alleen de cijfers intypen bijvoorbeeld, of drie cijfers in plaats van vier. En misschien is de potentiële klant gewoon helemaal vergeten de postcode in te vullen. We kunnen hem het beste zo veel mogelijk informatie geven en een beleefde aanduiding van wat we van hem verwachten: ‘Wilt u uw postcode invullen? Graag op de volgende manier: 1234 AB.’ De postcode is natuurlijk een relatief duidelijk veld om in te vullen. Maar denk bijvoorbeeld eens aan wat er allemaal mis kan gaan bij het invullen van een email-adres...
‘Postcode bestaat niet.’ Dat is ook wat kort en ruw. Daar kunnen we misschien ‘De door u opgegeven postcode bestaat niet.’ van maken. In een enkel geval zou het zo kunnen zijn dat het hier een bezoeker betreft die tóch gelijk heeft met wat hij heeft ingevuld, terwijl ons systeem het niet herkent. Dat is bijvoorbeeld mogelijk als hij woont in een Vinex-locatie, of in een gebied waar een postcode-herindeling heeft plaatsgevonden waar onze database nog niet van op de hoogte is. En dan is het vervelend als hij van ons de boodschap krijgt dat de postcode van zijn net opgeleverde huis niet bestaat. Daarom voegen we nog een regeltje toe, met een link: ‘Klopt uw postcode naar uw mening wél? Vul dan het formulier voor uw volledige adres in.’ Deze link leidt naar een aparte pagina waar hij zijn volledige adres kan invullen, zodat we de gegevens tóch binnenkrijgen.
‘Huisnummer missing.’ Tsja. Laten we daar een aardige Nederlandse zin van maken: ‘Wilt u uw huisnummer invullen?’
‘No match.’ Ook hier kunnen we meer informatie geven, waardoor de bezoeker beter weet wat er gebeurd is en wat hij er aan kan doen. We maken er van: ‘Het ingegeven huisnummer komt niet overeen met de ingegeven postcode.’
Tijd om te kijken naar een werkend voorbeeld (of bekijk de broncode van index.php en verify.inc.php).
Wij gebruiken de verstrekte gegevens alleen voor het toesturen van de brochure en één vervolgbrochure.
We hebben nu aan alles gedacht: een duidelijk doel dat we willen bereiken, een begrijpelijk formulier met een helder privacy statement, goede controles op de ingevulde velden en vriendelijke, behulpzame teksten voor als het onverhoopt misgaat. We kunnen dit formulier met een gerust hart aan onze klant overdragen en haar veel succes wensen met het opbouwen van nieuwe relaties!
ken je misschien als deel van de redactie van NAAR VOREN.
Wouter is in het dagelijkse leven software-ontwikkelaar. Sinds begin 2000 houdt hij het weblog Karma Universe bij. Verder ontwikkelt hij in z’n vrije tijd ook nog Nucleus
Marrije is zakelijk leider en informatie-architect bij eend. Daarnaast schrijft ze over boeken in Duck for Cover.
Robert Jan verdient zijn brood met eend en maakt zich geregeld druk over alles wat de bezoeker ten goede komt, want dat is ook goed voor de opdrachtgever.
Publicatiedatum: 09 februari 2005
Naar Voren is op 18 juli 2010 gestopt met publiceren. De artikelen staan als een soort archief online. Het kan dus zijn dat de informatie verouderd is en dat er inmiddels veel betere of makkelijkere manieren zijn om je doel te bereiken.
Copyright © 2002-heden » NAAR VOREN en de auteurs