Introducción a AJAX

6.1. Modelo básico de eventos

El modelo simple de eventos se introdujo en la versión 4 del estándar HTML y se considera parte del nivel más básico de DOM. Aunque sus características son limitadas, es el único modelo que es compatible con todos los navegadores y por tanto, el único que permite crear aplicaciones que funcionan de la misma manera en todos los navegadores.

6.1.1. Tipos de eventos

Cada elemento XHTML tiene definida su propia lista de posibles eventos que se le pueden asignar. Un mismo tipo de evento (por ejemplo, pinchar el botón izquierdo del ratón) puede estar definido para varios elementos XHTML y un mismo elemento XHTML puede tener asociados diferentes eventos.

El nombre de los eventos se construye mediante el prefijo on, seguido del nombre en inglés de la acción asociada al evento. Así, el evento de pinchar un elemento con el ratón se denomina onclick y el evento asociado a la acción de mover el ratón se denomina onmousemove.

La siguiente tabla resume los eventos más importantes definidos por JavaScript:

Evento Descripción Elementos para los que está definido
onblur Deseleccionar el elemento <button>, <input>, <label>, <select>, <textarea>, <body>
onchange Deseleccionar un elemento que se ha modificado <input>, <select>, <textarea>
onclick Pinchar y soltar el ratón Todos los elementos
ondblclick Pinchar dos veces seguidas con el ratón Todos los elementos
onfocus Seleccionar un elemento <button>, <input>, <label>, <select>, <textarea>, <body>
onkeydown Pulsar una tecla y no soltarla Elementos de formulario y <body>
onkeypress Pulsar una tecla Elementos de formulario y <body>
onkeyup Soltar una tecla pulsada Elementos de formulario y <body>
onload Página cargada completamente <body>
onmousedown Pulsar un botón del ratón y no soltarlo Todos los elementos
onmousemove Mover el ratón Todos los elementos
onmouseout El ratón "sale" del elemento Todos los elementos
onmouseover El ratón "entra" en el elemento Todos los elementos
onmouseup Soltar el botón del ratón Todos los elementos
onreset Inicializar el formulario <form>
onresize Modificar el tamaño de la ventana <body>
onselect Seleccionar un texto <input>, <textarea>
onsubmit Enviar el formulario <form>
onunload Se abandona la página, por ejemplo al cerrar el navegador <body>

Algunos de los eventos anteriores (onclick, onkeydown, onkeypress, onreset y onsubmit) permiten evitar el comportamiento por defecto del evento si se devuelve el valor false, tal y como se verá más adelante.

Por otra parte, las acciones típicas que realiza un usuario en una página web pueden dar lugar a una sucesión de eventos. Si se pulsa por ejemplo sobre un botón de tipo submit se desencadenan los eventos onmousedown, onmouseup, onclick y onsubmit.

6.1.2. Manejadores de eventos

En la programación orientada a eventos, las aplicaciones esperan a que se produzcan los eventos. Una vez que se produce un evento, la aplicación responde ejecutando cierto código especialmente preparado. Este tipo de código se denomina "manejadores de eventos" (del inglés "event handlers") y las funciones externas que se definen para responder a los eventos se suelen denominar "funciones manejadoras".

En las siguientes secciones se presentan las tres formas más utilizadas para indicar el código que se ejecuta cuando se produce un evento.

6.1.2.1. Manejadores como atributos XHTML

La forma más sencilla de incluir un manejador de evento es mediante un atributo de XHTML. El siguiente ejemplo muestra un mensaje cuando el usuario pincha en el botón:

<input type="button" value="Pinchame y verás" onclick="alert('Gracias por pinchar');" />
Página HTML

Figura 6.1 Página HTML

El usuario pincha con el ratón sobre el botón que se muestra

Figura 6.2 El usuario pincha con el ratón sobre el botón que se muestra

Después de pinchar con el ratón, se muestra un mensaje en una nueva ventana

Figura 6.3 Después de pinchar con el ratón, se muestra un mensaje en una nueva ventana

El método consiste en incluir un atributo XHTML con el mismo nombre del evento que se quiere procesar. En este caso, como se quiere mostrar un mensaje cuando se pincha con el ratón sobre un botón, el evento es onclick.

El contenido del atributo es una cadena de texto que contiene todas las instrucciones JavaScript que se ejecutan cuando se produce el evento. En este caso, el código JavaScript es muy sencillo, ya que solamente se trata de mostrar un mensaje mediante la función alert().

En este otro ejemplo, se muestra un mensaje cuando la página se ha cargado completamente:

<body onload="alert('La página se ha cargado completamente');">
...
</body>

El evento onload es uno de los más utilizados porque, como se vio en el capítulo de DOM, las funciones de acceso y manipulación de los nodos del árbol DOM solamente están disponibles cuando la página se carga por completo.

6.1.2.2. Manejadores de eventos y variable this

En los eventos de JavaScript, se puede utilizar la palabra reservada this para referirse al elemento XHTML sobre el que se está ejecutando el evento. Esta técnica es útil para ejemplos como el siguiente, en el que se modifican las propiedades del elemento que provoca el evento.

En el siguiente ejemplo, se muestra un borde destacado en el elemento <div> cuando el usuario pasa el ratón por encima. Cuando el ratón sale del <div>, se vuelve a mostrar el borde original:

<div id="elemento" style="padding: .2em; width: 150px; height: 60px; border: thin solid silver" onmouseover = "document.getElementById('elemento').style.borderColor = 'black'" onmouseout = "document.getElementById('elemento').style.borderColor = 'silver'">
  Sección de contenidos...
</div>

El evento onmouseover se activa cuando el ratón pasa por encima del elemento, en este caso el <div>. Para cambiar el color del borde, se utiliza la propiedad border-color de CSS. Por lo tanto, en primer lugar se obtiene la referencia del elemento mediante document.getElementById('elemento'). A continuación, se utiliza la propiedad style para acceder a las propiedades CSS y se modifica el nombre de border-color por el de borderColor. Para volver al color original cuando el ratón sale del elemento, se realiza la misma operación sobre el evento onmouseout.

El uso de la variable this puede simplificar todos estos pasos, ya que dentro de un manejador de eventos, la variable this equivale al elemento que ha provocado el evento. Así, la variable this es igual al <div> de la página y por tanto this.style.borderColor permite cambiar de forma directa el color del borde del <div>:

<div style="padding: .2em; width: 150px; height: 60px; border: thin solid silver" onmouseover="this.style.borderColor='black'" onmouseout="this.style.borderColor='silver'">
  Sección de contenidos...
</div>

Haciendo uso de la variable this, el código es mucho más sencillo de escribir, leer y mantener.

6.1.2.3. Manejadores de eventos como funciones externas

La definición de manejadores de eventos en los atributos XHTML es un método sencillo pero poco aconsejable para tratar con los eventos en JavaScript. El principal inconveniente es que se complica en exceso en cuanto se añaden algunas pocas instrucciones, por lo que solamente es recomendable para los casos más sencillos.

Cuando el código de la función manejadora es más complejo, como por ejemplo la validación de un formulario, es aconsejable agrupar todo el código JavaScript en una función externa que se invoca desde el código XHTML cuando se produce el evento.

De esta forma, el siguiente ejemplo:

<input type="button" value="Pinchame y verás" onclick="alert('Gracias por pinchar');" />

Se puede transformar en:

function muestraMensaje() {
  alert('Gracias por pinchar');
}

<input type="button" value="Pinchame y verás" onclick="muestraMensaje()" />

En las funciones externas no es posible utilizar la variable this de la misma forma que en los manejadores insertados en los atributos XHTML. Por tanto, es necesario pasar la variable this como parámetro a la función manejadora:

function resalta(elemento) {
  switch(elemento.style.borderColor) {
    case 'silver':
    case 'silver silver silver silver':
    case '#c0c0c0':
      elemento.style.borderColor = 'black';
      break;
    case 'black':
    case 'black black black black':
    case '#000000':
      elemento.style.borderColor = 'silver';
      break;
  }
}

<div style="padding: .2em; width: 150px; height: 60px; border: thin solid silver" onmouseover="resalta(this)" onmouseout="resalta(this)">
  Sección de contenidos...
</div>

En el ejemplo anterior, a la función externa se le pasa el parámetro this, que dentro de la función se denomina elemento. Al pasar this como parámetro, es posible acceder de forma directa desde la función externa a las propiedades del elemento que ha provocado el evento.

Por otra parte, el ejemplo anterior se complica por la forma en la que los distintos navegadores almacenan el valor de la propiedad borderColor. Mientras que Firefox almacena (en caso de que los cuatro bordes coincidan en color) el valor simple black, Internet Explorer lo almacena como black black black black y Opera almacena su representación hexadecimal #000000.

6.1.2.4. Manejadores de eventos semánticos

Utilizar los atributos XHTML o las funciones externas para añadir manejadores de eventos tiene un grave inconveniente: "ensucian" el código XHTML de la página.

Como es conocido, al crear páginas web se recomienda separar los contenidos (XHTML) de la presentación (CSS). En lo posible, también se recomienda separar los contenidos (XHTML) de la programación (JavaScript). Mezclar JavaScript y XHTML complica excesivamente el código fuente de la página, dificulta su mantenimiento y reduce la semántica del documento final producido.

Afortunadamente, existe un método alternativo para definir los manejadores de eventos de JavaScript. Esta técnica consiste en asignar las funciones externas mediante las propiedades DOM de los elementos XHTML. Así, el siguiente ejemplo:

<input id="pinchable" type="button" value="Pinchame y verás" onclick="alert('Gracias por pinchar');" />

Se puede transformar en:

function muestraMensaje() {
  alert('Gracias por pinchar');
}
document.getElementById("pinchable").onclick = muestraMensaje;

<input id="pinchable" type="button" value="Pinchame y verás" />

El código XHTML resultante es muy "limpio", ya que no se mezcla con el código JavaScript. La técnica de los manejadores semánticos consiste en:

  1. Asignar un identificador único al elemento XHTML mediante el atributo id.
  2. Crear una función de JavaScript encargada de manejar el evento.
  3. Asignar la función a un evento concreto del elemento XHTML mediante DOM.

Otra ventaja adicional de esta técnica es que las funciones externas pueden utilizar la variable this referida al elemento que original el evento.

Asignar la función manejadora mediante DOM es un proceso que requiere una explicación detallada. En primer lugar, se obtiene la referencia del elemento al que se va a asignar el manejador:

document.getElementById("pinchable");

A continuación, se asigna la función externa al evento deseado mediante una propiedad del elemento con el mismo nombre del evento:

document.getElementById("pinchable").onclick = ...

Por último, se asigna la función externa. Como ya se ha comentado en capítulos anteriores, lo más importante (y la causa más común de errores) es indicar solamente el nombre de la función, es decir, prescindir de los paréntesis al asignar la función:

document.getElementById("pinchable").onclick = muestraMensaje;

Si se añaden los paréntesis al final, en realidad se está invocando la función y asignando el valor devuelto por la función al evento onclick de elemento.

El único inconveniente de este método es que los manejadores se asignan mediante las funciones DOM, que solamente se pueden utilizar después de que la página se ha cargado completamente. De esta forma, para que la asignación de los manejadores no resulte errónea, es necesario asegurarse de que la página ya se ha cargado.

Una de las formas más sencillas de asegurar que cierto código se va a ejecutar después de que la página se cargue por completo es utilizar el evento onload:

window.onload = function() {
  document.getElementById("pinchable").onclick = muestraMensaje;
}

La técnica anterior utiliza una función anónima para asignar algunas instrucciones al evento onload de la página (en este caso se ha establecido mediante el objeto window). De esta forma, para asegurar que cierto código se va a ejecutar después de que la página se haya cargado, sólo es necesario incluirlo en el interior de la siguiente construcción:

window.onload = function() {
  ...
}

Ejercicio 10

A partir de la página web proporcionada y utilizando manejadores de eventos semánticos, completar el código JavaScript para que:

  1. Cuando se pinche sobre el primer enlace, se oculte su sección relacionada
  2. Cuando se vuelva a pinchar sobre el mismo enlace, se muestre otra vez esa sección de contenidos
  3. Completar el resto de enlaces de la página para que su comportamiento sea idéntico al del primer enlace

Cuando la sección se oculte, debe cambiar el mensaje del enlace asociado (pista: propiedad innerHTML).

Descargar archivo ZIP con la página HTML

Ver solución