Entrades etiquetades ‘javascript’

Validacions de formularis: a client o a servidor?

dijous 11 febrer 2010

Els que ens dediquem a sistemes client-servidor, més específicament, a sistemes basats en web,  sovint ens trobem amb la necessitat de construir formularis que executin accions a partir d’una entrada. És ben normal, que un client o un funcional proclami:

  • Vull que el número d’identificació sigui obligatori!
  • El correu electrònic ha d’estar en el format correcte!

O altres típics requeriments que requereixin de fer una validació del formulari.

Davant d’aquest escenari, el primer que ens ve al cap és fer les validacions amb JavaScript a la capa client. Bé, no està malament. Fer les validacions a la capa de client, és ràpid en temps de computació, senzill (normalment) i proporciona una resposta ràpida a l’usuari, fet pel qual assegurem una bona experiència d’usuari mentre introduïm dades. Una de les primeres normes de la usabilitat a formularis és: com més aviat sàpiga l’usuari que s’ha equivocat, més aviat podrà reaccionar-hi (compte amb la interpretació d’aquesta frase made-by-me!). Però mai hem d’acabar aquí!

Fer les validacions només a la capa client és una decisió completament errònia. On de debò s’han de fer aquestes comprovacions és a la capa servidor. Allà és on s’ha de mirar si cert camp existeix, si el format de tal camp és el correcte, de si la relació entre dos camps és correcta, etc. És a la capa servidor on tot aquest algorisme s’ha d’executar per prevenir qualsevol error que pugui tenir l’aplicació. És allà on s’executa la lògica de l’aplicació i on les validacions, com part d’aquesta lògica que són, s’han d’executar. Si només ho féssim a client, què passaria si no tinguéssim disponible el JavaScript? Quin seria el comportament de l’aplicació? Possiblement, acabéssim en un estat d’inconsistència no desitjat per ningú.

Sovint quan es planteja aquest argument (validacions dobles a capa client i servidor), molts arquitectes d’aplicacions (remarco la paraula perquè és el títol que es posen ells, no el que els hi posaria jo) posen el crit al cel i diuen la del porc argumentant que s’està fent una tasca dues vegades i que el rendiment de l’aplicació en general es veu ressentit. Si alguna vegada us trobeu davant d’això, només heu de dir:

D’acord, llavors, les validacions que es facin només a la capa de servidor!

Veureu com els hi canvia la cara ;)

Cal tenir ben presents quines són les implicacions de deixar un processament de dades a una capa tan fràgil com pot ser un navegador, i la nostra tasca és argumentar i deixar ben clar el per què a client no és lloc per fer aquest tipus de processament.

Tingueu aquest consell sempre ben present perquè segur que al llarg de la vostra vida professional us caldrà utilitzar-lo més d’un cop.

Comprovacions de l’existència d’una variable a JavaScript

dilluns 21 desembre 2009

Quan programem amb JavaScript (o qualsevol altre llenguatge de scripting) és normal haver de fer comprovacions de l’existència d’una variable dins de l’espai de noms.

Si necessitem saber si una variable ha estat declarada però sense valor assignat, podem comparar-la amb el “valor” undefined. Així podem veure:

var x;
// x === undefined retornaria cert
x = 5;
// x === undefined retornaria fals

Però si el que de debò volem fer és comprovar si aquesta variable ha estat definida en algun punt del script, no podem fer aquesta comprovació, ja que al intentar cercar el símbol “x” a la seva taula de noms, ens donaria un error de referència. Llavors, podem fer-ho o no? La resposta és sí! Només cal comprovar el seu tipus: si no té un tipus definit, vol dir que no està definida dins la taula de noms. Total, que podem fer:

// typeof(y) === undefined retornaria cert
var y;
// typeof(y) === undefined retornaria fals

I ja per acabar amb nota: com fer per saber si certa variable està definida directament en l’àmbit global de l’script? Doncs bé, com bé sabem, qualsevol variable definida a l’espai global, està també definida com un camp de l’objecte global. Llavors, els que ens dediquem a la programació web, i per tant tenim l’objecte window com a objecte global, podem fer la comprovació:

window.z === undefined
// retornaria cert si la variable z no ha estat definida

Doncs res, aquest ha estat el truc del dia. Espero que us sigui útil!

JavaScript. The Definitive Guide

dimarts 17 novembre 2009
Portada del llibre Javascript. The Definitive Guide

Portada del llibre Javascript. The Definitive Guide

Si alguna vegada esteu interessats en comprar un llibre sobre un llenguatge de programació i descobriu que un autor anomenat David Flanagan n’ha escrit un, no us ho penseu més: agafeu-lo. No tinc el plaer de conèixer-el en persona, però el que us puc ben assegurar és que aquest home, abans d’escriure res sobre un tema, ho estudia tot. I això us ho puc ben assegurar perquè no és pas el primer llibre que llegeixo d’aquest home i me n’adono de la minuciositat en que descriu un concepte o com va esfilagarsant un tema fins a deixar-lo tot explicat i ben explicat sobre paper.

El llibre que ens ocupa, JavaScript. The Definitive Guide, és per definició, el llibre de lectura obligatòria si volem intentar conèixer de debò aquest llenguatge de programació. Aquest llibre ens demostra que JavaScript no és, com la gent pensa, un llenguatge de programació només per la web i que només serveix per a validar formularis, fer menús desplegables i fer que la meva pàgina sigui més molona. No! JavaScript, i més d’un se sorprendrà al llegir això, és un dels llenguatges de programació més difícils i complexes que existeixen. Tampoc us espanteu, sinó que aquest llenguatge de programació amaga més d’una sorpresa, i fins que no llegeixes un llibre on s’explica tot amb pèls i senyals, no te n’adones de fins a on arriba el seu potencial.

Aquest llibre, com el seu nom indica, vol ser la guia definitiva de JavaScript, i sota el meu punt de vista, ho compleix sense cap tipus de dubte. La seva lectura, salvant la barrera inicial de ser un llibre de quasi bé un miler de pàgines escrites en anglès, es fa molt amena, avançant per tots els conceptes del llenguatge d’una forma natural i seguint un guió gens qüestionable, que ens durà, a través de centenars d’exemples, a comprendre parts completament desconegudes per molts.

Només mirant el llom interior del llibre, podem veure que aquest es divideix en quatre parts; encara que el llibre tracta només amb dos grans temes:

  • La primer part, anomenada Core JavaScript, tal i com el seu nom indica, explica el nucli del llenguatge amb un detall excepcional. En aquesta part podem trobar els següents capítols:
    • Lexical Structure
    • Datatypes and Values
    • Variables
    • Expressions and Operators
    • Statements
    • Objects and Arrays
    • Functions
    • Classes, Constructors, and Prototypes
    • Modules and Namespaces
    • Pattern Matching with Regular Expressions
    • Scripting Java
  • La segona part, anomenada Client-Side JavaScript, se centra més en el navegador com a plataforma de desenvolupament d’aplicacions en JavaScript. Hi podem trobar:
    • JavaScript in Web Browsers
    • Scripting Browser Windows
    • Scripting Documents
    • Cascading Style Sheets and Dynamic HTML
    • Events and Event Handling
    • Forms and Form Elements
    • Cookies and Client-Side Persistence
    • Scripting HTTP
    • JavaScript and XML
    • Scripted Client-Side Graphics
    • Scripting Java Applets and Flash Movies
  • La tercera part, anomenada Core JavaScript Reference, és una referència completa de totes les classe, objectes, mètodes, propietats i demés del nucli del llenguatge definits per JavaScript 1.5 i ECMAScript versió 3.
  • La quarta part, anomenada Client-Side JavaScript Reference, és una referència de tots els elements que podem trobar dins d’aquest tema, des de DOM (nivell 1, 2 i 3), canvas, etc.

Què, te’l compres? T’he convençut? Fes-ho, veuràs com em dones la raó de que és un llibre d’aquells que s’han de tenir sempre a mà.

Protegir pàgines amb l’event onbeforeunload

dimecres 9 setembre 2009

No us ha passat mai que mentre esteu acabant d’omplir un formulari, sense adonar-vos, feu clic allà on no toca i perdeu tot el que heu introduït? Doncs bé, hi ha una senzilla manera per evitar al màxim aquests errors: l’event onbeforeunload.

Cap allà als mitjans dels noranta, Internet Explorer 4.0 introduí aquest event no estàndard, però a diferència d’altres ocasions, aquest cop feu una cosa útil i els navegadors amb motor Gecko ho acabaren introduint a la versió 1.7 de Mozilla (Firefox 1.0).

Aquest event, tal i com resa el seu nom, es dispara just abans de l’event onunload, és a dir, abans que es descarregui el contingut actual de la pàgina, i per tant, ens permet executar algun tipus d’acció en aquest moment.

A diferència dels altres events, aquest funciona força diferent: per tal de mostrar un missatge a l’usuari abans de descarregar la pàgina, el que cal fer és retornar una cadena amb el missatge que es vulgui mostrar. Un exemple podria ser:


window.onbeforeunload = function(e) {
  return "No heu enviat el formulari. Si tanqueu la pàgina perdreu tots els canvis fets fins ara.";
}

Així, en cas d’abandonar la pàgina, se’ns mostraria un quadre amb el missatge:

Esteu segur que voleu sortir d’aquesta pàgina?

No heu enviat el formulari. Si tanqueu la pàgina perdreu tots els canvis fets fins ara.

Premeu D’acord per a continuar, o cancel·la per a romandre a la pàgina actual

Les frases que hi ha just abans i després de les nostres les posa el navegador (en aquest cas Firefox) i no es poden eliminar, substituir ni evitar de cap tipus de les maneres.

Val a dir que en cas que el navegador no tingui implementat aquest event, aquests simplement l’ignoraran i no mostraran pas el missatge a l’usuari.

Pàgines protegides

Recapitulem. La raó principal d’aquest article és que fa poc a la feina em varen demanar que implementés una funcionalitat per a protegir pàgines: volien poder mostrar un missatge quan un usuari intentés abandonar la pàgina enmig d’un formulari dins d’un procés amb un cert flux o bé intentés abandonar una pàgina, la construcció de la qual fos molt costosa. Un exemple ideal per a treure l’event onbeforeunload de la nostra cartera de recursos. Anem a construir-ho.

Per tal de poder marcar si una pàgina la tractem com a protegida o no, és a dir, si registrem l’event onbeforeunload per mostrar un missatge a l’usuari en cas d’abandonar la pàgina, afegirem la classe protected a l’element /body de la pàgina:

<body class="protected">

Així, si usem jQuery, podem afegir les següents línies de codi per a tenir-ho fet:

$('body.protected').each(function () {
  window.onbeforeunload = function(e){
    return "Si abandones, ho perdràs tot per sempre!";
  };
});

Però tenim un petit inconvenient: si fem clic en un enllaç o si enviem el formulari fent clic a un botó, se’ns mostrarà el missatge, cosa que volem evitar. Això es pot resoldre inhabilitant l’event en cas de fer clic a certs elements:

$('body.protected p.botons input, body.protected a.sense-onbeforeunload', context).click(function () {
  window.onbeforeunload = null;
});

I així de fàcil obtenim el que busquem. Fàcil, oi? I segur que a més d’un li sembla útil, i fins i tot, més que necessari en alguna situació quotidiana.

Recursos

Com fer un plugin per a jQuery. Contingut tabulat en pestanyes

dimecres 22 juliol 2009

Durant el meu dia a dia professional, treballo (i força) amb jQuery, una meravellosa biblioteca JavaScript (s’entreveuen les meves preferències, oi?). Doncs bé, la segona cosa que cal saber quan s’entra en el món jQuery és desenvolupar, o com a mínim conèixer l’estructura bàsica, d’un plugin.

Per a exemplificar la construcció, crearem un petit giny per a construir contingut tabulat en pestanyes.

Partim d’un fragment HTML com el següent:

<div class="pestanyes">
  <h2>Pestanya 1</h2>
  <div>
    ...contingut...
  </div>
  <h2>Pestanya 2</h2>
  <div>
    ...contingut de la segona...
  </div>
  <h2>Pestanya 3</h2>
  <div>
    ...i una mica més...
  </div>
</div>

Si ens centrem en el giny, podríem redactar una petita explicació funcional com la següent:

  • En estat de repòs, es mostren les pestanyes amb la primera activa i només es mostra el contingut relacionat amb aquesta.
  • Una vegada cliquem a una pestanya, aquesta passa a ser l’activa i el contingut que es mostra passa a ser el relacionat amb aquesta.

Ara només falta traduir això a codi JavaScript.

Comencem creant l’estructura general del plugin:

$('.pestanyes').each(function() {
  ...
});

I les estructures necessàries per a crear el giny. Primer de tot caldrà amagar les capçaleres i el contingut d’aquestes i crear l’estructura per a les pestanyes que a nosaltres ens sigui còmode de treballar-hi. Per exemple una d’ideal seria una senzilla llista <ul><li>...</li></ul>.

Anem a passar tot això a codi JavaScript:

$('div.pestanyes').each(function () {
  // creem una referència a les capçaleres i al contingut de les pestanyes
  var $headings = $('h2', this);
  var $content = $headings.next();

  // amaguem les capçaleres i els continguts
  $headings.hide();
  $content.hide();

  // creem l'estructura de les pestanyes
  var tabHtml = '';
  $headings.each(function() {
    tabHtml += '<li>' + $(this).text() + '<\/li>';
  });

  // i l'afegim al document
  $(this).prepend('<ul class="tabs">' + tabHtml + '<\/ul>');
}

Una vegada creada l’estructura, només queda marcar l’estat inicial amb la primera pestanya i el seu contingut relacionat com a actius:

var $tabs = $('ul.tabs li');
$tabs.eq(0).addClass('active');
$content.eq(0).show();

Ara només ens queda centrar-nos en la interacció amb les pestanyes. Quan un usuari faci clic en una pestanya, cal resetejar l’estat actual (eliminar la marca d’actiu) i marcar la pestanya que s’ha clicat com a activa, juntament amb el seu contingut relacionat.

$tabs.click(function() {
  // eliminem la classe i amaguem el contingut
  $tabs.removeClass('active');
  $content.hide();

  // marquem la pestanya activa i mostrem el contingut que calgui
  $(this).addClass('active');
  var tabIndex = $tabs.index(this);
  $content.eq(tabIndex).show();
});

Si ho posem tot junt, podem veure el resultat i una aplicació a un cas a l’exemple.

Però fins aquí no hem fet res de res per construir un plugin. Posem-nos a treballar-hi.

Adaptació del codi per a ser un plugin vàlid

Quan pensem en crear un plugin jQuery, el que ens ve al cap és crear una funcionalitat reutilitzable dins del domini d’un objecte jQuery, és a dir, estendre l’objecte. Així, si ens centrem en el nostre exemple, la idea és acabar creant un codi tal que per poder crear un contingut tabulat, hàgim d’escriure simplement:

$('div.pestanyes').tabs();

Si el que volem és estendre l’objecte jQuery el que haurem de fer, igual que en qualsevol altre objecte JavaScript, és afegir una nova propietat al seu objecte prototype. Així, una cosa d’aquest tipus seria vàlid:

$.prototype.tabs = function () {
  // el nostre codi
}

Però si hagués decidit fer-ho així, ja s’hauria acabat l’entrada, i aquesta no és pas la idea.

Si mirem les primeres línies de la biblioteca jQuery, podem veure la creació d’un alies força interessant:

jQuery.fn = jQuery.prototype

Així, si volem usar aquesta notació, podem ampliar directament l’objecte tot fent:

$.fn.tabs = function () {
  // el meu codi
  return this;
}

S’ha afegit el retorn del propi objecte per a poder permetre l’encadenament de crides:

$('#element')
  .tabs()
  .mesCoses();

El plugin que estem construint és força senzill, però què passaria si tinguéssim variables globals, funcions auxiliars i demés? Alguna cosa com aquesta:

var foo = 0;
$.fn.myPlugin = function () {
  foo += 5;
  myMethod();
  return this;
}
function myMethod() {
  ...
}

Amb aquest escenari, algú sense gaires llums (o amb ganes de tocar la pera) podria usar el plugin des la següent forma (i des de l’espai global de noms):

var myMethod = 'bar';
$('#element').myPlugin();

Però per sort, nosaltres tenim un as sota la màniga anomenat closure. Així, podem englobar tot el codi del nostre plugin dins d’una funció anònima:

(function () {
  var foo = 0;
  $.fn.myPlugin = function () {
    foo += 5;
    myMethod();
    return this;
  }
  function myMethod() {
    ...
  }
}) ();

Sembla que tot ja està fet, no? Queda un últim punt. Per a assegurar la compatibilitat amb d’altres biblioteques, no podem usar l’àlies de l’objecte jQuery $ així com així, sinó que hauríem d’usar jQuery com a mètode d’accés a l’objecte. Però això no és gaire còmode, no? Tranquils! Aprofitant que tenim la funció anònima englobant el nostre codi, podem crear un àlies segur per a jQuery fàcilment passant-lo com a paràmetre d’aquesta:

(function($) {
  ...
})(jQuery);

Ara ja estem en condicions de crear el nostre primer plugin. Podeu veure el codi resultant a l’exemple.

Ampliacions

Una vegada que tenim el plugin funcionant, ens podem centrar en fer-lo més real. El primer que ens podem preguntar és: què és un plugin sense opcions? Doncs si en volem, només cal donar-li un parell de voltes i fet.

Considerem dues opcions de configuració:

  • Pestanya activada per defecte, que serà un enter (per defecte 0) que indicarà l’index de la pestanya (activatedIndex)
  • Efecte visual al canviar de pestanya, que serà el nom d’una funció (per defecte null) dins l’espai de noms de l’objecte jQuery (animation)

I si ho afegim al codi que ja tenim:

$.fn.tabs = function (options) {
  var config = $.extend({
    activatedIndex: 0,
    animation: null
  }, options || {});

  ...
}

Ara el mètode tabs accepta un paràmetre que és un objecte de configuració. S’usa el mètode $.extend per tal d’estendre un objecte amb els valors per defecte amb els passats com a paràmetre.

Ara, els únics canvis que cal fer són força trivials. Pel cas de l’índex de la pestanya a activar:

// marquem la pestanya i el contingut desat a la configuració com actiu
var $tabs = $('ul.tabs li');
$tabs.eq(config.activatedIndex).addClass('active');
$content.eq(config.activatedIndex).show();

I pel cas de l’animació al canviar de pestanya:

if(config.animation) {
  $content.eq(tabIndex)[config.animation]();
} else {
  $content.eq(tabIndex).show();
}

I per acabar, només falta veure-ho tot ajuntat i funcionant al seu exemple corresponent.

Fonts

No creieu pas que sóc un geni. Ni molt menys. Aquesta entrada està basada en una de molt millor del meu amic Choan, el qual em va iniciar en el meravellós món del JavaScript. Només he volgut explicar-ho des de la meva òptica, usant alguna que altra alternativa de notació i amb un exemple ben diferent.

Cal deixar ben clar que això no és pas un plugin oficial ni res per l’estil. El codi el teniu disponible per tocar i jugar, però no s’acceptaran cap tipus de culpa per l’ús d’aquest en algun entorn productiu.

El que sí que s’accepten són notes, comentaris i tot el que vulgueu fer sobre el que aquí s’ha exposat.