maandag 10 juni 2013

Alleen invoer van getallen accepteren

Vaak heb je in webpagina’s invoervakken nodig waarin uitsluitend cijfers mogen worden getypt. Denk bijvoorbeeld aan aantallen, jaartallen en bedragen. Hoe voorkom je dat gebruikers iets anders invoeren dan getallen? Met wat minified JavaScript is dat zó opgelost.

Toetsen afvangen met JavaScript

JavaScript biedt je verschillende mogelijkheden voor het maken van een event listener: een procedure die reageert op het optreden van een bepaalde gebeurtenis. De volgende JavaScript-functie isNumeriekeToets() controleert of er op een cijfertoets is gedrukt.

function isNumeriekeToets(gebeurtenis)
{
  var karakter = (gebeurtenis.which) ? gebeurtenis.which : gebeurtenis.keyCode;
  if (karakter > 31 && (karakter < 48 || karakter > 57)) {
    return false;
  } else {
    return true;
  }
}

In HTML kun je deze JavaScript-functie aanroepen door er bij het optreden van een gebeurtenis zoals onkeypress het sleutelwoord event aan door te geven:

<input name="..." onkeypress="return isNumeriekeToets(event)" type="text">

Is de aangeslagen toets een cijfer, dan wordt het toegevoegd aan het invoervak. Is de toets bijvoorbeeld een letter of een leesteken, dan wordt het karakter genegeerd.

Minified JavaScript

Een nadeel van JavaScript is dat alle JavaScript-code via internet naar een client moet worden verzonden. Elke byte is er een te veel voor snelle webpagina’s. Een oplossing is de scriptcode minified te maken.

Om te beginnen kunnen we de twee variabelennamen gebeurtenis en karakter vervangen door één letter. We kunnen bijvoorbeeld de letters a en b gebruiken, net als in de algebra:

function isNumeriekeToets(a)
{
  var b = (a.which) ? a.which : a.keyCode;
  if (b > 31 && (b < 48 || b > 57)) {
    return false;
  } else {
    return true;
  }
}

Logische controlestructuren en de ternary operator

JavaScript is niet mijn favoriete computertaal. De scripttaal JavaScript lijkt namelijk evenveel op een echte programmeertaal als slootwater op koffie lijkt. JavaScript is geen Java.

Toch werkt veel in JavaScript hetzelfde als in een echte programmeertaal. Als je netjes programmeert, gebruik je bijvoorbeeld liever nooit een if zonder else. Een uitzondering is een controlestructuur met een return, want met return wordt een functie onmiddellijk verlaten. Dat geldt in JavaScript en bijvoorbeeld ook in PHP. De else in de functie is overbodig. De volgende variant van de JavaScript-functie retourneert nog steeds altijd true of false, ook zonder een else:

function isNumeriekeToets(a)
{
  var b = (a.which) ? a.which : a.keyCode;
  if (b > 31 && (b < 48 || b > 57)) {
    return false;
  }
  return true;
}

Wil je de logica van een if inclusief een else liever handhaven? Dan kan dat met de ternary operator, een logische operator die drie argumenten accepteert. In pseudocode is de ternary operator meestal het snelst te doorzien. Een controlestructuur met if en else zoals:

if (x) {
  y;
} else {
  z;
}

kun je met de ternary operator schrijven als:

x ? y : z;

Met de ternary operator kunnen we de return van de functie herschrijven tot één expressie:

function isNumeriekeToets(a)
{
  var b = (a.which) ? a.which : a.keyCode;
  return (b > 31 && (b < 48 || b > 57)) ? false : true;
}

Micro-optimalisatie

Onze JavaScript-functie is inmiddels lekker compact, maar de ware minimalist schuwt micro-optimalisatie niet. Elke byte is er, zoals gezegd, een te veel. In plaats van de leesbare maar lange functienaam isNumeriekeToets() kunnen we bijvoorbeeld isNum() gebruiken. In zowel het Engels als het Nederlands is num onder ontwikkelaars de gebruikelijke afkorting voor een numerieke waarde:

function isNum(a)
{
  var b = (a.which) ? a.which : a.keyCode;
  return (b > 31 && (b < 48 || b > 57)) ? false : true;
}

Deze kortere functienaam levert een extra besparing op. Niet alleen verkorten we hiermee de functiedefinitie, maar ook elke functieaanroep. Een HTML-tag waarin de functie wordt aangeroepen, kan hiermee worden verkort tot bijvoorbeeld:

<input name="..." onkeypress="return isNum(event)" type="text">

Om de functie helemaal minified te maken, kunnen we tot slot alle overbodige white space of witruimte verwijderen. Naast inspringen zijn dat vooral regeleinden en spaties rond accolades en operatoren. Daarmee krijgen we tot slot deze functie:

function isNum(a){var b=(a.which)?a.which:a.keyCode;return(b>31&&(b<48||b>57))?false:true};

Tip! Vind je zelf minified JavaScript schrijven te veel werk? Het kan ook grotendeels automatisch met bijvoorbeeld de Online JavaScript/CSS Compression Using YUI Compressor, een website die gebruikmaakt van YUI Compressor van Yahoo!’s Exceptional Performance Team.

Geen opmerkingen:

Een reactie posten