Javascript

Javascript

1. VARIABLES

TiposVariables         variable

Una variable es un elemento que se emplea para almacenar y hacer referencia a otro valor.

Estructura:          nombre_variable = contenido;

Se declara con la palabra reservada var:

var nombre_variable = 40;

Se puede declarar sin valor de inicio y darle valor en otro lugar del programa:

 var nombre;

Ejemplos:

      numero = 456 ;  // contenido numérico

      cadena = “hola mundo”;   // contenido cadena de texto o string

(tiene que ir entre comillas).

      suma = 4 + 7;  // puede contener operaciones aritméticas

      resultado = suma * 10; // puede almacenar otra variable.

      decimales = 23.9; // puede tener contenido decimal.

      dato = true;       dato = false;     // puede tener valor booleano.

 

 

2. OPERADORES

operadores

Los permiten manipular el valor de las variables, realizar operaciones matemática con sus valores y compara diferentes variable. De esta forma, los operadores permiten a los programas realizar cálculos complejos y tomar decisiones lógicas en función de comparaciones y otros tipos de condiciones.

 

2.1 Asignación

 

se utiliza para guardar un valor específico en una variable. El símbolo utilizado es =

ejemplo:

var valor = 5;

 

2.2 Incremento y decremento

 

Estos dos operadores solamente son válidos para las variables numéricas y se utilizan para incrementar o decrementar en una unidad el valor de una variable.

operador de incremento (++) aumentaría en uno el valor del contenido de la variable.

ejemplo:

        var numero = 5;
        ++numero;
        alert(numero);  // numero = 6

El operador del ejemplo (++numero;) equivale a numero=numero+1 de esta forma lo abreviamos.

De forma equivalente, el operador decremento (indicado como un prefijo -- en el nombre de la variable) se utiliza para diminuir el valor de la variable:

       var numero = 5;
       --numero;
       alert(numero);  // numero = 4

Aquí algunos ejemplo de combinar estos operadores:

           var numero1 = 5;
           var numero2 = 2;
           numero3 = numero1++ + numero2;
           // numero3 = 7, numero1 = 6
 
          var numero1 = 5;
          var numero2 = 2;
          numero3 = ++numero1 + numero2;
         // numero3 = 8, numero1 = 6


2.3 Lógicos

logicos

Los operadores lógicos son imprescindibles para realizar aplicaciones complejas, ya que se utilizan para tomar decisiones sobre las instrucciones que debería ejecutar el programa en función de ciertas condiciones.

El resultado de cualquier operación que utilice operadores lógicos siempre es un valor lógico o booleano.

 

      Negación

Se utiliza para obtener el valor contrario al valor de la variable:

 

var visible = true; alert(!visible); // Muestra “false” y no “true”

La negación lógica se obtiene prefijando el símbolo ! al identificador de la variable.

Aquí se ve el comportamiento del operador dependiendo del valor de la variable:

variable !variable
true false
false true

 AND

La operación lógica AND obtiene su resultado combinando valores booleanos. El operador se indica mediante el símbolo && y su resultado solamente es true si todo los operandos son true:

variable1 variable2 variable1 && variable2
true true true
true false false
false true false
false false false

Ejemplos:

           var valor1 = true;
           var valor2 = false;
           resultado = valor1 && valor2; // resultado = false
 
           valor1 = true;
           valor2 = true;
           resultado = valor1 && valor2; // resultado = true

OR

La operación lógica OR también combina valores booleanos. El operador se indica mediante el símbolo || y su resultado es true si alguno de los operandos es true:

variable1 variable2 variable1 || variable2
true true true
true false true
false true true
false false false

Ejemplo:

         var valor1 = true;
         var valor2 = false;
         resultado = valor1 || valor2; // resultado = true
 
         valor1 = false;
         valor2 = false;
         resultado = valor1 || valor2; // resultado = false

2.4 Matemáticos

aritmeticos

suma (+), resta (-), multiplicación (*) , división (/), módulo(%), Ejemplo:

 

         var numero1 = 10;
         var numero2 = 5;
 
            resultado = numero1 / numero2;  // resultado = 2
            resultado = 3 + numero1;        // resultado = 13
            resultado = numero2 – 4;        // resultado = 1
            resultado = numero1 * numero 2; // resultado = 50
            resultado = numero1 % numero2; // resultado = 0 (calcula el resto de la división entera de dos números..) 

Los operadores matemáticos también se pueden combinar con el operador de asignación para abreviar su notación:

var numero1 = 5;
numero1 += 3;  // numero1 = numero1 + 3 = 8
numero1 -= 1;  // numero1 = numero1 - 1 = 4
numero1 *= 2;   // numero1 = numero1 * 2 = 10
numero1 /= 5;   // numero1 = numero1 / 5 = 1
numero1 %= 4;   // numero1 = numero1 % 4 = 1


2.5 Relacionales

condicionalescomparacion

mayor que (>), menor que (<), mayor o igual (>=), menor o igual (<=), igual que (==) y distinto de (!=). El resultado de todos estos operadores siempre es un valor booleano:

var numero1 = 3;
var numero2 = 5;
resultado = numero1 > numero2; // resultado = false
resultado = numero1 < numero2; // resultado = true
 
numero1 = 5;
numero2 = 5;
resultado = numero1 >= numero2; // resultado = true
resultado = numero1 <= numero2; // resultado = true
resultado = numero1 == numero2; // resultado = true
resultado = numero1 != numero2; // resultado = false
Distinción entre operador "=" y opreador "==":
// El operador "=" asigna valores
var numero1 = 5;
resultado = numero1 = 3;  // numero1 = 3 y resultado = 3
 
// El operador "==" compara variables
var numero1 = 5;
resultado = numero1 == 3; // numero1 = 5 y resultado = false

se pueden utilizar con variables de tipo cadena de texto:

var texto1 = "hola";
var texto2 = "hola";
resultado = texto1 != texto2; // resultado = false

3. Estructuras de control de flujo

 

Las estructuras de control, denominadas también sentencias de control, permiten tomar decisiones y realizar un proceso repetidas veces. Se trata de estructuras muy importantes, ya que son las encargadas de controlar el flujo de un programa, según los requerimientos del mismo.

instrucciones del tipo“si se cumple esta condición, hazlo; si no se cumple, haz esto otro”. También existen instrucciones del tipo “repite esto mientras se cumpla esta condición”.

3.1 Estructura if / if…else

if_else

 

Estructura:

if(condicion) {
  ...bloque de código a ejecutar
}
Si la condición se cumple se ejecuta el código que hay entre las llaves.
Ejemplo:

var mostrarMensaje = true;   if(mostrarMensaje) { alert(“Hola Mundo”); }

el mensaje sí que se muestra al usuario ya que la variable mostrarMensaje tiene un valor de truey por tanto, el programa entra dentro del bloque de instrucciones del if.

if/else

if (condición) {
   código_A
}
else {
   código_B
}
Veamos lo que tenemos aquí. Primero, comprobamos la condición en la que vamos a basar nuestra decisión (veremos más adelante cómo crear condiciones). Si la condición es válida (si es verdadera), se ejecutará el primer bloque de código que está entre llaves ({}); si no, se 
ejecutará el siguiente bloque de código, el que se encuentra debajo de la palabra else. Es
 decir, si la condición es verdadera, ejecutamos código_A, y si no, código_B.

Ejemplo:

var edad = 18;
if (edad >= 18) {
   alert("Eres mayor de edad");
}
else {
   alert("Eres menor de edad");
}

Primero definimos la variable edad con el valor numérico 18. Después comprobamos si el sujeto es o no mayor de edad leyendo el valor de la variable: si edad es mayor o igual que 18, entonces le decimos que es mayor de edad; si no, le decimos que es menor de edad.

alert es una función de Javascript que nos permite mostrar un mensaje en pantalla.

Pero, ¿qué ocurre cuando queremos hacer varias comprobaciones al mismo tiempo? Entonces podemos usar la instrucción else if.

if (edad > 18) {
   alert("Tienes más de 18 años");
}
else if (edad == 18) {
   alert("Tienes 18 años");
}
else {
   alert("Tienes menos de 18 años");
}

De esta forma, podemos extender las condiciones todo lo que queramos para cubrir todos los casos necesarios. Hay que destacar que todas las condiciones son sucesivas y que sólo se ejecuta una de ellas. Además, el último else es el que se ejecuta en el caso de que ninguno de los if anteriores sea válido.

3.4 Estructura for

El bucle FOR se utiliza para repetir una o más instrucciones un determinado número de veces. De entre todos los bucles, el FOR se suele utilizar cuando sabemos seguro el número de veces que queremos que se ejecute. La sintaxis del bucle for se muestra a continuación.

for (inicialización; condición; actualización) {
//sentencias a ejecutar en cada iteración
}

El bucle FOR tiene tres partes incluidas entre los paréntesis, que nos sirven para definir cómo deseamos que se realicen las repeticiones. La primera parte es la inicialización, que se ejecuta solamente al comenzar la primera iteración del bucle. En esta parte se suele colocar la variable que utilizaremos para llevar la cuenta de las veces que se ejecuta el bucle.

La segunda parte es la condición, que se evaluará cada vez que comience una iteración del bucle. Contiene una expresión para decidir cuándo se ha de detener el bucle, o mejor dicho, la condición que se debe cumplir para que continúe la ejecución del bucle.

Por último tenemos la actualización, que sirve para indicar los cambios que queramos ejecutar en las variables cada vez que termina la iteración del bucle, antes de comprobar si se debe seguir ejecutando.

Después del for se colocan las sentencias que queremos que se ejecuten en cada iteración, acotadas entre llaves.

ejemplo:

var i
for (i=0;i<=10;i++) {
document.write(i)
document.write(“<br>”)
}

3.5 Bucle for … in

En Javascript hay una construcción especial del bucle for de toda la vida, que te permite recorrer todas las propiedades de un objeto. Es parecido a lo que en otros lenguajes tenemos en el bucle foreach (Javascript también tiene el forEach pero es solo para arrays y no es un bucle sino un método de arrays, que sirve para iterar, pero no es una estructura de control como tal). Su sintaxis es la siguiente:

for (propiedad in objeto){

//código a repetir por el bucle. //dentro de este código la variable "propiedad" contiene la propiedad actual //actual en cada uno de los pasos de la iteración.

}

3.6 Bucle DO…WHILE

El bucle do…while es la última de las estructuras para implementar repeticiones de las que dispone en Javascript y es una variación del bucle while visto anteriormente. Se utiliza generalmente cuando no sabemos cuantas veces se habrá de ejecutar el bucle, igual que el bucle WHILE, con la diferencia de que sabemos seguro que el bucle por lo menos se ejecutará una vez.

do {
    //sentencias del bucle
} while (condición)

ejemplo:

var color
do {
    color = prompt(“dame un color (escribe rojo para salir)”,””)
} while (color != “rojo”) 

3.7 Bucle WHILE

Estos bucles se utilizan cuando queremos repetir la ejecución de unas sentencias un número indefinido de veces, siempre que se cumpla una condición. Se más sencillo de comprender que el bucle FOR, pues no incorpora en la misma línea la inicialización de las variables su condición para seguir ejecutándose y su actualización. Sólo se indica, como veremos a continuación, la condición que se tiene que cumplir para que se realice una iteración.

while (condición){
//sentencias a ejecutar
}

ejemplo;:

var color = “”
while (color != “rojo”){
color = prompt(“dame un color (escribe rojo para salir)”,””)
}

3.8 estructura de control switch

La estructura de control switch de Javascript es utilizada para tomar decisiones en función de distintos estados o valores de una variable.

Es un poco más compleja que permite hacer múltiples operaciones dependiendo del estado de una variable.

switch (expresión) {
case valor1:
Sentencias a ejecutar si la expresión tiene como valor a valor1
break
case valor2:
Sentencias a ejecutar si la expresión tiene como valor a valor2
break
case valor3:
Sentencias a ejecutar si la expresión tiene como valor a valor3
break
default:
Sentencias a ejecutar si el valor no es ninguno de los anteriores
}

ejemplo:

 

var dia_de_la_semana = 2;

switch (dia_de_la_semana) {
    case 1:
       document.write(“Es Lunes”)
       break
    case 2:
       document.write(“Es Martes”)
       break
    case 3:
       document.write(“Es Miércoles”)
       break
    case 4:
       document.write(“Es Jueves”)
       break
    case 5:
       document.write(“Es viernes”)
       break
    case 6:
    case 7:
       document.write(“Es fin de semana”)
       break
    default:
       document.write(“Ese día no existe”)
}

En este caso ejecutaría el caso número 2 (case 2: document.write(“Es martes”);

4.Funciones y propiedades básicas de JavaScript

JavaScript incorpora una serie de herramientas y utilidades (llamadas funciones y propiedades, como se verá más adelante) para el manejo de las variables. De esta forma, muchas de las operaciones básicas con las variables, se pueden realizar directamente con las utilidades que ofrece JavaScript.

length, calcula la longitud de una cadena de texto (el número de caracteres que la forman)

var mensaje = "Hola Mundo";
var numeroLetras = mensaje.length; // numeroLetras = 10

+, se emplea para concatenar varias cadenas de texto

var mensaje1 = "Hola";
var mensaje2 = " Mundo";
var mensaje = mensaje1 + mensaje2; // mensaje = "Hola Mundo"

Además del operador +, también se puede utilizar la función concat()

var mensaje1 = "Hola";
var mensaje2 = mensaje1.concat(" Mundo"); // mensaje2 = "Hola Mundo"

Las cadenas de texto también se pueden unir con variables numéricas:

var variable1 = "Hola ";
var variable2 = 3;
var mensaje = variable1 + variable2; // mensaje = "Hola 3"

Cuando se unen varias cadenas de texto es habitual olvidar añadir un espacio de separación entre las palabras:

var mensaje1 = "Hola";
var mensaje2 = "Mundo";
var mensaje = mensaje1 + mensaje2; // mensaje = "HolaMundo"

Los espacios en blanco se pueden añadir al final o al principio de las cadenas y también se pueden indicar forma explícita:

var mensaje1 = "Hola";
var mensaje2 = "Mundo";
var mensaje = mensaje1 + " " + mensaje2; // mensaje = "Hola Mundo"

toUpperCase(), transforma todos los caracteres de la cadena a sus correspondientes caracteres en mayúsculas:

var mensaje1 = "Hola";
var mensaje2 = mensaje1.toUpperCase(); // mensaje2 = "HOLA"

toLowerCase(), transforma todos los caracteres de la cadena a sus correspondientes caracteres en minúsculas:

var mensaje1 = "HolA";
var mensaje2 = mensaje1.toLowerCase(); // mensaje2 = "hola"

charAt(posicion), obtiene el carácter que se encuentra en la posición indicada:

var mensaje = "Hola";
var letra = mensaje.charAt(0); // letra = H
letra = mensaje.charAt(2);     // letra = l

indexOf(caracter), calcula la posición en la que se encuentra el carácter indicado dentro de la cadena de texto. Si el carácter se incluye varias veces dentro de la cadena de texto, se devuelve su primera posición empezando a buscar desde la izquierda. Si la cadena no contiene el carácter, la función devuelve el valor -1:

var mensaje = "Hola";
var posicion = mensaje.indexOf('a'); // posicion = 3
posicion = mensaje.indexOf('b');     // posicion = -1

Su función análoga es lastIndexOf():

lastIndexOf(caracter), calcula la última posición en la que se encuentra el carácter indicado dentro de la cadena de texto. Si la cadena no contiene el carácter, la función devuelve el valor -1:

var mensaje = "Hola";
var posicion = mensaje.lastIndexOf('a'); // posicion = 3
posicion = mensaje.lastIndexOf('b');     // posicion = -1

La función lastIndexOf() comienza su búsqueda desde el final de la cadena hacia el principio, aunque la posición devuelta es la correcta empezando a contar desde el principio de la palabra.

substring(inicio, final), extrae una porción de una cadena de texto. El segundo parámetro es opcional. Si sólo se indica el parámetro inicio, la función devuelve la parte de la cadena original correspondiente desde esa posición hasta el final:

var mensaje = "Hola Mundo";
var porcion = mensaje.substring(2); // porcion = "la Mundo"
porcion = mensaje.substring(5);     // porcion = "Mundo"
porcion = mensaje.substring(7);     // porcion = "ndo"

Si se indica un inicio negativo, se devuelve la misma cadena original:

var mensaje = "Hola Mundo";
var porcion = mensaje.substring(-2); // porcion = "Hola Mundo"

Cuando se indica el inicio y el final, se devuelve la parte de la cadena original comprendida entre la posición inicial y la inmediatamente anterior a la posición final (es decir, la posición inicio está incluida y la posición final no):

var mensaje = "Hola Mundo";
var porcion = mensaje.substring(1, 8); // porcion = "ola Mun"
porcion = mensaje.substring(3, 4);     // porcion = "a"

Si se indica un final más pequeño que el inicio, JavaScript los considera de forma inversa, ya que automáticamente asigna el valor más pequeño al inicio y el más grande al final:

var mensaje = "Hola Mundo";
var porcion = mensaje.substring(5, 0); // porcion = "Hola "
porcion = mensaje.substring(0, 5);     // porcion = "Hola "

split(separador), convierte una cadena de texto en un array de cadenas de texto. La función parte la cadena de texto determinando sus trozos a partir del carácter separador indicado:

var mensaje = "Hola Mundo, soy una cadena de texto!";
var palabras = mensaje.split(" ");
// palabras = ["Hola", "Mundo,", "soy", "una", "cadena", "de", "texto!"];

Con esta función se pueden extraer fácilmente las letras que forman una palabra:

var palabra = "Hola";
var letras = palabra.split(""); // letras = ["H", "o", "l", "a"]

4.1 Funciones útiles para arrays

length, calcula el número de elementos de un array

var vocales = ["a", "e", "i", "o", "u"];
var numeroVocales = vocales.length; // numeroVocales = 5

concat(), se emplea para concatenar los elementos de varios arrays

var array1 = [1, 2, 3];
array2 = array1.concat(4, 5, 6);   // array2 = [1, 2, 3, 4, 5, 6]
array3 = array1.concat([4, 5, 6]); // array3 = [1, 2, 3, 4, 5, 6]

join(separador), es la función contraria a split(). Une todos los elementos de un array para formar una cadena de texto. Para unir los elementos se utiliza el carácter separador indicado

var array = ["hola", "mundo"];
var mensaje = array.join(""); // mensaje = "holamundo"
mensaje = array.join(" ");    // mensaje = "hola mundo"

pop(), elimina el último elemento del array y lo devuelve. El array original se modifica y su longitud disminuye en 1 elemento.

var array = [1, 2, 3];
var ultimo = array.pop();
// ahora array = [1, 2], ultimo = 3

push(), añade un elemento al final del array. El array original se modifica y aumenta su longitud en 1 elemento. (También es posible añadir más de un elemento a la vez)

var array = [1, 2, 3];
array.push(4);
// ahora array = [1, 2, 3, 4]

shift(), elimina el primer elemento del array y lo devuelve. El array original se ve modificado y su longitud disminuida en 1 elemento.

var array = [1, 2, 3];
var primero = array.shift();
// ahora array = [2, 3], primero = 1

unshift(), añade un elemento al principio del array. El array original se modifica y aumenta su longitud en 1 elemento. (También es posible añadir más de un elemento a la vez)

var array = [1, 2, 3];
array.unshift(0);
// ahora array = [0, 1, 2, 3]

reverse(), modifica un array colocando sus elementos en el orden inverso a su posición original:

var array = [1, 2, 3];
array.reverse();
// ahora array = [3, 2, 1]

4.2 Funciones útiles para números

A continuación se muestran algunas de las funciones y propiedades más útiles para el manejo de números.

NaN, (del inglés, “Not a Number”) JavaScript emplea el valor NaN para indicar un valor numérico no definido (por ejemplo, la división 0/0).

var numero1 = 0;
var numero2 = 0;
alert(numero1/numero2); // se muestra el valor NaN

isNaN(), permite proteger a la aplicación de posibles valores numéricos no definidos

var numero1 = 0;
var numero2 = 0;
if(isNaN(numero1/numero2)) {
  alert("La división no está definida para los números indicados");
}
else {
  alert("La división es igual a => " + numero1/numero2);
}

Infinity, hace referencia a un valor numérico infinito y positivo (también existe el valor –Infinity para los infinitos negativos)

var numero1 = 10;
var numero2 = 0;
alert(numero1/numero2); // se muestra el valor Infinity

toFixed(digitos), devuelve el número original con tantos decimales como los indicados por el parámetro digitos y realiza los redondeos necesarios. Se trata de una función muy útil por ejemplo para mostrar precios.

var numero1 = 4564.34567;
numero1.toFixed(2); // 4564.35
numero1.toFixed(6); // 4564.345670
numero1.toFixed(); // 4564

5.Programación avanzada

5.1. Funciones

javascript

Las funciones son uno de los elementos más importantes de cualquier lenguaje de programación actual. De hecho, Niklaus Wirth, uno de los más importantes teóricos de la programación y creador del lenguaje Pascal entre otros, llegó a indicar que todo programa no era más que la suma de código (rutinas, procedimientos o funciones, como se les quiera llamar) y datos (variables, matrices, etc…). Sea como sea, las funciones tienen un papel estelar en el desarrollo de aplicaciones en la actualidad.

Hasta ahora, hemos visto como realizar código de una forma estructurada, con sentencias de control que nos permiten dominar la ejecución del mismo fácilmente. Pero si sólo tenemos esto, solamente podremos manejar el código de forma lineal: ejecutaremos las líneas una a una, una detrás de la otra, hasta el final del programa. Es más, si quisiéramos usar un determinado código varias veces en el mismo programa tendríamos que repetir ese código varias veces, teniéndolo que adaptar a cada situación. ¿Y qué ocurre si queremos reutilizar un código en varios programas? Es un problema que se resuelven gracias a las funciones.

Las funciones son trozos de código que tienen un nombre y que podemos utilizar en cualquier parte de nuestro código con una llamada directa. Este es un buen ejemplo:

function datos_personales(nombre, apellidos, edad) {

return “Hola, ” + nombre + ” ” + apellidos + “, tienes ” + edad + ” años.”;

}

En este caso hemos definido una función que, usando los parámetros que le hemos pasado, los combina para formar una cadena formateada, que devuelve gracias a la palabra reservada return. ¿Y cómo podemos usar este código?

alert(datos_personales(‘Pepito’, ‘Pérez’, 25));

De tal forma que primero ejecutaremos la función datos_personales con los parámetros pasados, y después la función alert, que nos permite mostrar una ventana con un mensaje en la pantalla, con el resultado devuelto por la función que hemos creado.

Los parámetros son un elemento importante en las funciones. Se trata de datos que podemos pasar a nuestras funciones para que estas los procesen de alguna forma, lo cual dará como resultado o una salida en el navegador (texto o ventanas), o bien un resultado que se puede usar cuando llamemos a la función. Cuando indiquemos parámetros, deberemos indicar la lista completa de parámetros que vamos a usar en esa función. Al llamar a la función, deberemos hacerlo con todos los parámetros indicados. De otra forma, se produciría un error de ejecución. Los parámetros se convierten en variables de datos dentro de la función, de ahí que podamos utilizarlas e incluso modificarlas.

Generalmente, las funciones se utilizan para realizar alguna operación no visible (matemática, de cadena de caracteres, de objetos, etc…) que devuelve por medio de return, pero también se pueden visualizar elementos en el navegador usando las funciones y objetos que ya incorpora JavaScript.

5.2 Funciones con parámetros

Como ya indicamos en el capítulo anterior, los parámetros nos sirven para llamar a nuestras funciones con unos datos específicos para que los procese. Y en cada llamada, podemos darle unos parámetros diferentes, que harán que pueda comportarse de forma diferente, si ese es el comportamiento que le hemos programado.

var numero = 1;

var cadena = “Hi!”;

var logico = true;

function valores(num, cad, log) {

document.write(num);

document.write(cad);

document.write(log); }

valores(numero, cadena, logico);

Esta función la estamos llamando con variables como parámetros, pero también podemos llamar a la función con valores literales, es decir, valores simples directos:

valores(2, “adiós”, false);

Como ya vimos en el capítulo anterior, también podemos hacer que otra función sea un parámetro:

valores(3, “que tal”.length, true);

“que tal”.length es una función que forma parte de los objetos de cadena de texto (todo, desde las variables hasta los literales, son objetos en JavaScript), y nos devuelve la longitud de una cadena de texto. En concreto, al hacer esta llamada nos devolverá un número ‘7’. Como las variables en JavaScript no tienen tipo (todas son objetos), podemos pasar cualquier valor como parámetro.

 

5.3 Devolución de datos

Como ya sabemos, una función puede devolver datos hacia afuera por medio de la expresión return. Naturalmente, podemos devolver cualquier tipo de datos. Sin embargo hay que tener en cuenta una serie de cuestiones:

  • Siempre se devuelven objetos, como ya hemos visto, y por lo tanto podemos devolver un objeto creado en la misma función. Normalmente, cuando creamos una variable dentro de una función, esta variable existe sólo para esa función, y desaparece en el momento en que la función termina (la variable se encuentra en la pila de memoria, y cuando la función desaparece, también lo hace la pila); pero en el caso de que devolvamos el objeto, no se devuelve exactamente la misma variable, si no que se devuelve su contenido.
  • Cuando devolvemos true ó un valor distinto que cero, para JavaScript es lo mismo, y si devolvemos false o 0, también viene a ser lo mismo. Esta es una regla estándar para muchos lenguajes como JavaScript, Java, PHP, Perl, etc…
  • No es preciso que una función devuelva nada. No es necesario usar return. Además, también es posible que en vez de devolver resultados, se modifiquen variables globales, es decir, variables creadas fuera de la función y que se usan dentro.
  • Si queremos salir de una función antes de tiempo, porque algo ha fallado o no hay nada que hacer en un caso específico, podemos simplemente escribir “return;”, lo que nos permitirá salir sin más y no devolver ningún valor.
  • function dev_variable() {

  • variable = true;

  • return variable;

  • }

  • var var1 = dev_variable();

  • Como vemos, hemos declarado una variable local a la función y la hemos devuelto, pero solo se devuelve realmente el valor. Esto pasa en todos los casos.

5.4 Funciones recursivas

Las funciones recursivas son aquellas que se llaman a sí mismas. Existen multitud de técnicas para desarrollar este tipo de funciones, ya que sus usos son muy diversos, pero fundamentalmente hay que tener en consideración que son funciones peligrosas, porque si no controlamos su ejecución, se estarán ejecutando indefinidamente, como en el caso de los bucles infinitos. La diferencia con los bucles infinitos es que dependiendo de la implementación del intérprete de JavaScript, es posible que rompamos la pila de memoria, que ya vimos antes, con lo que además de colgar el navegador, podemos generar una excepción de memoria y un error grave del sistema. Para evitarlo, claro está, debemos estudiar bien la lógica de la función para construirla adecuadamente. Por ejemplo, si queremos calcular el factorial de un número, podemos hacerlo con una función recursiva:

function factorial(numero) {

if (numero == 1 || numero == 0) return 1;

else

return numero*factorial(numero – 1);

}

document.write(factorial(4));

Supóngase la llamada a esta función para N=4, es decir factorial(4). Cuando se llame por primera vez a la función, la variable numero valdrá 4, y por tanto devolverá el valor de 4*factorial(3); pero factorial(3) devolverá 3*factorial(2); factorial(2) a su vez es 2*factorial(1) y dado que factorial(1) es igual a 1 (es importante considerar que sin éste u otro caso particular, llamado caso base, la función recursiva no terminaría nunca de llamarse a sí misma), el resultado final será 4*(3*(2*1)).

 

6. Ámbito de las variables

Las variables locales se definen dentro de una función y solo se tiene acceso dentro de la misma función. Una variable local se la define antecediendo la palabra clave var al nombre de la variable.

function imprimir() {

var x=10; document.write(x);

}

imprimir();

Luego decimos que x es una variable local que solo se la puede acceder dentro de la función imprimir. Si intentamos acceder a la variable x fuera de la función se produce un error en tiempo de ejecución:

function imprimir() {

var x=10; document.write(x);

}

imprimir();

document.write(x); //error en tiempo de ejecución

Las variables globales son las que definimos fuera de cualquier función. Una variable global tenemos acceso fuera y dentro de las funciones:

function imprimir() {

document.write(global1+'<br>’); // muestra un 100

global1++;

} var global1=100;

imprimir();

document.write(global1); // muestra un 101

 

7. Sentencias break y continue

images (41)

Los comandos break y continue sirven para optimizar los ciclos for y while, así como para el operador condicional if.

El comando break, de hecho, interrumpe un bloque de instrucciones saltando a la primera instrucción que sigue al bloque que contiene el break. Un uso apropiado evitará la formación de loop sin salida:

function interrumpe() {
while (x>0) {
if (x>3)
break; //aquí la instrucción se interrumpe y sale del if
x++;
}
return x;
}

El ejemplo muestra cómo el ciclo continúa incrementando la variable x hasta que ésta llega a ser superior a 3, en cuyo caso encuentra la instrucción breakque interrumpe el ciclo y continúa con la instrucción que sigue al bloque (return x;).

El comando continue, por su parte, indica que se continue el bloque pero interrumpiendo la iteración en ese punto y volviendo a comenzar desde el inicio del bloque.

while (x<10) {
x++;
if (x>3)
continue;
a+=x;
}

El ejemplo muestra cómo el ciclo se repite si x es inferior a 10, mientras que si es igual a 8, la instrucción continue interrumpe el ciclo y vuelve a empezar desde el principio.

 8. DOM

image025images (30)images (58)

 

La creación del Document Object Model o DOM es una de las innovaciones que más ha influido en el desarrollo de las páginas web dinámicas y de las aplicaciones web más complejas.

DOM permite a los programadores web acceder y manipular las páginas XHTML como si fueran documentos XML. De hecho, DOM se diseñó originalmente para manipular de forma sencilla los documentos XML.

A pesar de sus orígenes, DOM se ha convertido en una utilidad disponible para la mayoría de lenguajes de programación (Java, PHP, JavaScript) y cuyas únicas diferencias se encuentran en la forma de implementarlo.

8.1. Árbol de nodos

Una de las tareas habituales en la programación de aplicaciones web con JavaScript consiste en la manipulación de las páginas web. De esta forma, es habitual obtener el valor almacenado por algunos elementos (por ejemplo los elementos de un formulario), crear un elemento (párrafos, <div>, etc.) de forma dinámica y añadirlo a la página, aplicar una animación a un elemento (que aparezca/desaparezca, que se desplace, etc.).

Todas estas tareas habituales son muy sencillas de realizar gracias a DOM. Sin embargo, para poder utilizar las utilidades de DOM, es necesario “transformar” la página original. Una página HTML normal no es más que una sucesión de caracteres, por lo que es un formato muy difícil de manipular. Por ello, los navegadores web transforman automáticamente todas las páginas web en una estructura más eficiente de manipular.

Esta transformación la realizan todos los navegadores de forma automática y nos permite utilizar las herramientas de DOM de forma muy sencilla. El motivo por el que se muestra el funcionamiento de esta transformación interna es que condiciona el comportamiento de DOM y por tanto, la forma en la que se manipulan las páginas.

DOM transforma todos los documentos XHTML en un conjunto de elementos llamados nodos, que están interconectados y que representan los contenidos de las páginas web y las relaciones entre ellos. Por su aspecto, la unión de todos los nodos se llama “árbol de nodos”.

La siguiente página XHTML sencilla:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Página sencilla</title>
</head>
 
<body>
<p>Esta página es <strong>muy sencilla</strong></p>
</body>
</html>

Se transforma en el siguiente árbol de nodos:

Árbol de nodos generado automáticamente por DOM a partir del código XHTML de la página

Figura 5.1 Árbol de nodos generado automáticamente por DOM a partir del código XHTML de la página

En el esquema anterior, cada rectángulo representa un nodo DOM y las flechas indican las relaciones entre nodos. Dentro de cada nodo, se ha incluido su tipo (que se verá más adelante) y su contenido.

La raíz del árbol de nodos de cualquier página XHTML siempre es la misma: un nodo de tipo especial denominado“Documento”.

A partir de ese nodo raíz, cada etiqueta XHTML se transforma en un nodo de tipo “Elemento”. La conversión de etiquetas en nodos se realiza de forma jerárquica. De esta forma, del nodo raíz solamente pueden derivar los nodosHEAD y BODY. A partir de esta derivación inicial, cada etiqueta XHTML se transforma en un nodo que deriva del nodo correspondiente a su “etiqueta padre”.

La transformación de las etiquetas XHTML habituales genera dos nodos: el primero es el nodo de tipo “Elemento”(correspondiente a la propia etiqueta XHTML) y el segundo es un nodo de tipo “Texto” que contiene el texto encerrado por esa etiqueta XHTML.

Así, la siguiente etiqueta XHTML:

<title>Página sencilla</title>

Genera los siguientes dos nodos:

Nodos generados automáticamente por DOM para una etiqueta XHTML sencilla

Figura 5.2 Nodos generados automáticamente por DOM para una etiqueta XHTML sencilla

De la misma forma, la siguiente etiqueta XHTML:

<p>Esta página es <strong>muy sencilla</strong></p>

Genera los siguientes nodos:

  • Nodo de tipo “Elemento” correspondiente a la etiqueta <p>.
  • Nodo de tipo “Texto” con el contenido textual de la etiqueta <p>.
  • Como el contenido de <p> incluye en su interior otra etiqueta XHTML, la etiqueta interior se transforma en un nodo de tipo “Elemento” que representa la etiqueta <strong> y que deriva del nodo anterior.
  • El contenido de la etiqueta <strong> genera a su vez otro nodo de tipo “Texto” que deriva del nodo generado por<strong>.

Nodos generados automáticamente por DOM para una etiqueta XHTML con otras etiquetas XHTML en su interior

Figura 5.3 Nodos generados automáticamente por DOM para una etiqueta XHTML con otras etiquetas XHTML en su interior

La transformación automática de la página en un árbol de nodos siempre sigue las mismas reglas:

  • Las etiquetas XHTML se transforman en dos nodos: el primero es la propia etiqueta y el segundo nodo es hijo del primero y consiste en el contenido textual de la etiqueta.
  • Si una etiqueta XHTML se encuentra dentro de otra, se sigue el mismo procedimiento anterior, pero los nodos generados serán nodos hijo de su etiqueta padre.

Como se puede suponer, las páginas XHTML habituales producen árboles con miles de nodos. Aun así, el proceso de transformación es rápido y automático, siendo las funciones proporcionadas por DOM (que se verán más adelante) las únicas que permiten acceder a cualquier nodo de la página de forma sencilla e inmediata.

8.2. Tipos de nodos

La especificación completa de DOM define 12 tipos de nodos, aunque las páginas XHTML habituales se pueden manipular manejando solamente cuatro o cinco tipos de nodos:

  • Document, nodo raíz del que derivan todos los demás nodos del árbol.
  • Element, representa cada una de las etiquetas XHTML. Se trata del único nodo que puede contener atributos y el único del que pueden derivar otros nodos.
  • Attr, se define un nodo de este tipo para representar cada uno de los atributos de las etiquetas XHTML, es decir, uno por cada par atributo=valor.
  • Text, nodo que contiene el texto encerrado por una etiqueta XHTML.
  • Comment, representa los comentarios incluidos en la página XHTML.

Los otros tipos de nodos existentes que no se van a considerar son DocumentType, CDataSection, DocumentFragment,Entity, EntityReference, ProcessingInstruction y Notation.

8.3. Acceso directo a los nodos

Una vez construido automáticamente el árbol completo de nodos DOM, ya es posible utilizar las funciones DOM para acceder de forma directa a cualquier nodo del árbol. Como acceder a un nodo del árbol es equivalente a acceder a “un trozo” de la página, una vez construido el árbol, ya es posible manipular de forma sencilla la página: acceder al valor de un elemento, establecer el valor de un elemento, mover un elemento de la página, crear y añadir nuevos elementos, etc.

DOM proporciona dos métodos alternativos para acceder a un nodo específico: acceso a través de sus nodos padre y acceso directo.

Las funciones que proporciona DOM para acceder a un nodo a través de sus nodos padre consisten en acceder al nodo raíz de la página y después a sus nodos hijos y a los nodos hijos de esos hijos y así sucesivamente hasta el último nodo de la rama terminada por el nodo buscado. Sin embargo, cuando se quiere acceder a un nodo específico, es mucho más rápido acceder directamente a ese nodo y no llegar hasta él descendiendo a través de todos sus nodos padre.

Por ese motivo, no se van a presentar las funciones necesarias para el acceso jerárquico de nodos y se muestran solamente las que permiten acceder de forma directa a los nodos.

Por último, es importante recordar que el acceso a los nodos, su modificación y su eliminación solamente es posible cuando el árbol DOM ha sido construido completamente, es decir, después de que la página XHTML se cargue por completo. Más adelante se verá cómo asegurar que un código JavaScript solamente se ejecute cuando el navegador ha cargado entera la página XHTML.

8.3.1. getElementsByTagName()

Como sucede con todas las funciones que proporciona DOM, la función getElementsByTagName() tiene un nombre muy largo, pero que lo hace autoexplicativo.

La función getElementsByTagName(nombreEtiqueta) obtiene todos los elementos de la página XHTML cuya etiqueta sea igual que el parámetro que se le pasa a la función.

El siguiente ejemplo muestra cómo obtener todos los párrafos de una página XHTML:

var parrafos = document.getElementsByTagName("p");

El valor que se indica delante del nombre de la función (en este caso, document) es el nodo a partir del cual se realiza la búsqueda de los elementos. En este caso, como se quieren obtener todos los párrafos de la página, se utiliza el valordocument como punto de partida de la búsqueda.

El valor que devuelve la función es un array con todos los nodos que cumplen la condición de que su etiqueta coincide con el parámetro proporcionado. El valor devuelto es un array de nodos DOM, no un array de cadenas de texto o un array de objetos normales. Por lo tanto, se debe procesar cada valor del array de la forma que se muestra en las siguientes secciones.

De este modo, se puede obtener el primer párrafo de la página de la siguiente manera:

var primerParrafo = parrafos[0];

De la misma forma, se podrían recorrer todos los párrafos de la página con el siguiente código:

for(var i=0; i<parrafos.length; i++) {
  var parrafo = parrafos[i];
}

La función getElementsByTagName() se puede aplicar de forma recursiva sobre cada uno de los nodos devueltos por la función. En el siguiente ejemplo, se obtienen todos los enlaces del primer párrafo de la página:

var parrafos = document.getElementsByTagName("p");
var primerParrafo = parrafos[0];
var enlaces = primerParrafo.getElementsByTagName("a");

8.3.2. getElementsByName()

La función getElementsByName() es similar a la anterior, pero en este caso se buscan los elementos cuyo atributo namesea igual al parámetro proporcionado. En el siguiente ejemplo, se obtiene directamente el único párrafo con el nombre indicado:

var parrafoEspecial = document.getElementsByName("especial");
 
<p name="prueba">...</p>
<p name="especial">...</p>
<p>...</p>

Normalmente el atributo name es único para los elementos HTML que lo definen, por lo que es un método muy práctico para acceder directamente al nodo deseado. En el caso de los elementos HTML radiobutton, el atributo name es común a todos los radiobutton que están relacionados, por lo que la función devuelve una colección de elementos.

Internet Explorer 6.0 no implementa de forma correcta esta función, ya que sólo la tiene en cuenta para los elementos de tipo <input> y <img>. Además, también tiene en consideración los elementos cuyo atributo id sea igual al parámetro de la función.

8.3.3. getElementById()

La función getElementById() es la más utilizada cuando se desarrollan aplicaciones web dinámicas. Se trata de la función preferida para acceder directamente a un nodo y poder leer o modificar sus propiedades.

La función getElementById() devuelve el elemento XHTML cuyo atributo id coincide con el parámetro indicado en la función. Como el atributo id debe ser único para cada elemento de una misma página, la función devuelve únicamente el nodo deseado.

var cabecera = document.getElementById("cabecera");
 
<div id="cabecera">
  <a href="/" id="logo">...</a>
</div>

La función getElementById() es tan importante y tan utilizada en todas las aplicaciones web, que casi todos los ejemplos y ejercicios que siguen la utilizan constantemente.

Internet Explorer 6.0 también interpreta incorrectamente esta función, ya que devuelve también aquellos elementos cuyo atributo name coincida con el parámetro proporcionado a la función.

8.4. Creación y eliminación de nodos

Acceder a los nodos y a sus propiedades (que se verá más adelante) es sólo una parte de las manipulaciones habituales en las páginas. Las otras operaciones habituales son las de crear y eliminar nodos del árbol DOM, es decir, crear y eliminar “trozos” de la página web.

8.4.1. Creación de elementos XHTML simples

Como se ha visto, un elemento XHTML sencillo, como por ejemplo un párrafo, genera dos nodos: el primer nodo es de tipo Element y representa la etiqueta <p> y el segundo nodo es de tipo Text y representa el contenido textual de la etiqueta <p>.

Por este motivo, crear y añadir a la página un nuevo elemento XHTML sencillo consta de cuatro pasos diferentes:

  1. Creación de un nodo de tipo Element que represente al elemento.
  2. Creación de un nodo de tipo Text que represente el contenido del elemento.
  3. Añadir el nodo Text como nodo hijo del nodo Element.
  4. Añadir el nodo Element a la página, en forma de nodo hijo del nodo correspondiente al lugar en el que se quiere insertar el elemento.

De este modo, si se quiere añadir un párrafo simple al final de una página XHTML, es necesario incluir el siguiente código JavaScript:

// Crear nodo de tipo Element
var parrafo = document.createElement("p");
 
// Crear nodo de tipo Text
var contenido = document.createTextNode("Hola Mundo!");
 
// Añadir el nodo Text como hijo del nodo Element
parrafo.appendChild(contenido);
 
// Añadir el nodo Element como hijo de la pagina
document.body.appendChild(parrafo);

El proceso de creación de nuevos nodos puede llegar a ser tedioso, ya que implica la utilización de tres funciones DOM:

  • createElement(etiqueta): crea un nodo de tipo Element que representa al elemento XHTML cuya etiqueta se pasa como parámetro.
  • createTextNode(contenido): crea un nodo de tipo Text que almacena el contenido textual de los elementos XHTML.
  • nodoPadre.appendChild(nodoHijo): añade un nodo como hijo de otro nodo. Se debe utilizar al menos dos veces con los nodos habituales: en primer lugar se añade el nodo Text como hijo del nodo Element y a continuación se añade el nodo Element como hijo de algún nodo de la página.

8.4.2. Eliminación de nodos

Afortunadamente, eliminar un nodo del árbol DOM de la página es mucho más sencillo que añadirlo. En este caso, solamente es necesario utilizar la función removeChild():

var parrafo = document.getElementById("provisional");
parrafo.parentNode.removeChild(parrafo);
 
<p id="provisional">...</p>

La función removeChild() requiere como parámetro el nodo que se va a eliminar. Además, esta función debe ser invocada desde el elemento padre de ese nodo que se quiere eliminar. La forma más segura y rápida de acceder al nodo padre de un elemento es mediante la propiedad nodoHijo.parentNode.

Así, para eliminar un nodo de una página XHTML se invoca a la función removeChild() desde el valor parentNode del nodo que se quiere eliminar. Cuando se elimina un nodo, también se eliminan automáticamente todos los nodos hijos que tenga, por lo que no es necesario borrar manualmente cada nodo hijo.

8.5. Acceso directo a los atributos XHTML

Una vez que se ha accedido a un nodo, el siguiente paso natural consiste en acceder y/o modificar sus atributos y propiedades. Mediante DOM, es posible acceder de forma sencilla a todos los atributos XHTML y todas las propiedades CSS de cualquier elemento de la página.

Los atributos XHTML de los elementos de la página se transforman automáticamente en propiedades de los nodos. Para acceder a su valor, simplemente se indica el nombre del atributo XHTML detrás del nombre del nodo.

El siguiente ejemplo obtiene de forma directa la dirección a la que enlaza el enlace:

var enlace = document.getElementById("enlace");
alert(enlace.href); // muestra http://www...com
 
<a id="enlace" href="http://www...com">Enlace</a>

En el ejemplo anterior, se obtiene el nodo DOM que representa el enlace mediante la funcióndocument.getElementById(). A continuación, se obtiene el atributo href del enlace mediante enlace.href. Para obtener por ejemplo el atributo id, se utilizaría enlace.id.

Las propiedades CSS no son tan fáciles de obtener como los atributos XHTML. Para obtener el valor de cualquier propiedad CSS del nodo, se debe utilizar el atributo style. El siguiente ejemplo obtiene el valor de la propiedad marginde la imagen:

var imagen = document.getElementById("imagen");
alert(imagen.style.margin);
 
<img id="imagen" style="margin:0; border:0;" src="logo.png" />

Aunque el funcionamiento es homogéneo entre distintos navegadores, los resultados no son exactamente iguales, como muestran las siguientes imágenes que son el resultado de ejecutar el código anterior en distintos navegadores:

Valores que muestra Internet Explorer al acceder a las propiedades CSS a través de JavaScript

Figura 5.4 Valores que muestra Internet Explorer al acceder a las propiedades CSS a través de JavaScript

Valores que muestra Firefox al acceder a las propiedades CSS a través de JavaScript

Figura 5.5 Valores que muestra Firefox al acceder a las propiedades CSS a través de JavaScript

Si el nombre de una propiedad CSS es compuesto, se accede a su valor modificando ligeramente su nombre:

var parrafo = document.getElementById("parrafo");
alert(parrafo.style.fontWeight);  // muestra "bold"
 
<p id="parrafo" style="font-weight: bold;">...</p>

La transformación del nombre de las propiedades CSS compuestas consiste en eliminar todos los guiones medios (-) y escribir en mayúscula la letra siguiente a cada guión medio. A continuación se muestran algunos ejemplos:

  • font-weight se transforma en fontWeight
  • line-height se transforma en lineHeight
  • border-top-style se transforma en borderTopStyle
  • list-style-image se transforma en listStyleImage

El único atributo XHTML que no tiene el mismo nombre en XHTML y en las propiedades DOM es el atributo class. Como la palabra class está reservada por JavaScript, no es posible utilizarla para acceder al atributo class del elemento XHTML. En su lugar, DOM utiliza el nombre className para acceder al atributo class de XHTML:

var parrafo = document.getElementById("parrafo");
alert(parrafo.class); // muestra "undefined"
alert(parrafo.className); // muestra "normal"
 
<p id="parrafo" class="normal">...</p>

9. Eventos

descarga (7)images (59)

Hasta ahora, todas las aplicaciones y scripts que se han creado tienen algo en común: se ejecutan desde la primera instrucción hasta la última de forma secuencial. Gracias a las estructuras de control de flujo (if, for, while) es posible modificar ligeramente este comportamiento y repetir algunos trozos del script y saltarse otros trozos en función de algunas condiciones.

Este tipo de aplicaciones son poco útiles, ya que no interactúan con los usuarios y no pueden responder a los diferentes eventos que se producen durante la ejecución de una aplicación. Afortunadamente, las aplicaciones web creadas con el lenguaje JavaScript pueden utilizar el modelo de programación basada en eventos.

En este tipo de programación, los scripts se dedican a esperar a que el usuario “haga algo” (que pulse una tecla, que mueva el ratón, que cierre la ventana del navegador). A continuación, el script responde a la acción del usuario normalmente procesando esa información y generando un resultado.

Los eventos hacen posible que los usuarios transmitan información a los programas. JavaScript define numerosos eventos que permiten una interacción completa entre el usuario y las páginas/aplicaciones web. La pulsación de una tecla constituye un evento, así como pinchar o mover el ratón, seleccionar un elemento de un formulario, redimensionar la ventana del navegador, etc.

JavaScript permite asignar una función a cada uno de los eventos. De esta forma, cuando se produce cualquier evento, JavaScript ejecuta su función asociada. Este tipo de funciones se denominan “event handlers” en inglés y suelen traducirse por “manejadores de eventos”.

9.2. Modelo básico de eventos

9.2.1. Tipos de eventos

En este modelo, cada elemento o etiqueta XHTML define 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 diferentes y un mismo elemento XHTML puede tener asociados varios eventos diferentes.

El nombre de cada evento 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 (sin soltar) 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 La página se ha cargado completamente <body>
onmousedown Pulsar (sin soltar) un botón del ratón Todos los elementos
onmousemove Mover el ratón Todos los elementos
onmouseout El ratón “sale” del elemento (pasa por encima de otro elemento) Todos los elementos
onmouseover El ratón “entra” en el elemento (pasa por encima del elemento) Todos los elementos
onmouseup Soltar el botón que estaba pulsado en el ratón Todos los elementos
onreset Inicializar el formulario (borrar todos sus datos) <form>
onresize Se ha modificado el tamaño de la ventana del navegador <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>

Los eventos más utilizados en las aplicaciones web tradicionales son onload para esperar a que se cargue la página por completo, los eventos onclick, onmouseover, onmouseout para controlar el ratón y onsubmit para controlar el envío de los formularios.

Algunos eventos de la tabla anterior (onclick, onkeydown, onkeypress, onreset, onsubmit) permiten evitar la “acción por defecto” de ese evento. Más adelante se muestra en detalle este comportamiento, que puede resultar muy útil en algunas técnicas de programación.

Las acciones típicas que realiza un usuario en una página web pueden dar lugar a una sucesión de eventos. Al pulsar por ejemplo sobre un botón de tipo <input type="submit"> se desencadenan los eventos onmousedown, onclick,onmouseup y onsubmit de forma consecutiva.

9.2.2. Manejadores de eventos

Un evento de JavaScript por sí mismo carece de utilidad. Para que los eventos resulten útiles, se deben asociar funciones o código JavaScript a cada evento. De esta forma, cuando se produce un evento se ejecuta el código indicado, por lo que la aplicación puede responder ante cualquier evento que se produzca durante su ejecución.

Las funciones o código JavaScript que se definen para cada evento se denominan “manejador de eventos” y como JavaScript es un lenguaje muy flexible, existen varias formas diferentes de indicar los manejadores:

  • Manejadores como atributos de los elementos XHTML.
  • Manejadores como funciones JavaScript externas.
  • Manejadores “semánticos”.

9.2.2.1. Manejadores de eventos como atributos XHTML

Se trata del método más sencillo y a la vez menos profesional de indicar el código JavaScript que se debe ejecutar cuando se produzca un evento. En este caso, el código se incluye en un atributo del propio elemento XHTML. En el siguiente ejemplo, se quiere mostrar un mensaje cuando el usuario pinche con el ratón sobre un botón:

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

En este método, se definen atributos XHTML con el mismo nombre que los eventos que se quieren manejar. El ejemplo anterior sólo quiere controlar el evento de pinchar con el ratón, cuyo nombre es onclick. Así, el elemento XHTML para el que se quiere definir este evento, debe incluir un atributo llamado 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 (alert('Gracias por pinchar');), ya que solamente se trata de mostrar un mensaje.

En este otro ejemplo, cuando el usuario pincha sobre el elemento <div> se muestra un mensaje y cuando el usuario pasa el ratón por encima del elemento, se muestra otro mensaje:

<div onclick="alert('Has pinchado con el ratón');" onmouseover="alert('Acabas de pasar el ratón por encima');">
  Puedes pinchar sobre este elemento o simplemente pasar el ratón por encima
</div>

Este otro ejemplo incluye una de las instrucciones más utilizadas en las aplicaciones JavaScript más antiguas:

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

El mensaje anterior se muestra después de que la página se haya cargado completamente, es decir, después de que se haya descargado su código HTML, sus imágenes y cualquier otro objeto incluido en la página.

El evento onload es uno de los más utilizados ya que, como se vio en el capítulo de DOM, las funciones que permiten acceder y manipular los nodos del árbol DOM solamente están disponibles cuando la página se ha cargado completamente.

9.2.2.2. Manejadores de eventos y variable this

JavaScript define una variable especial llamada this que se crea automáticamente y que se emplea en algunas técnicas avanzadas de programación. En los eventos, se puede utilizar la variable this para referirse al elemento XHTML que ha provocado el evento. Esta variable es muy útil para ejemplos como el siguiente:

Cuando el usuario pasa el ratón por encima del <div>, el color del borde se muestra de color negro. Cuando el ratónsale del <div>, se vuelve a mostrar el borde con el color gris claro original.

Elemento <div> original:

<div id="contenidos" style="width:150px; height:60px; border:thin solid silver">
  Sección de contenidos...
</div>

Si no se utiliza la variable this, el código necesario para modificar el color de los bordes, sería el siguiente:

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

El código anterior es demasiado largo y demasiado propenso a cometer errores. Dentro del código de un evento, JavaScript crea automáticamente la variable this, que hace referencia al elemento XHTML que ha provocado el evento. Así, el ejemplo anterior se puede reescribir de la siguiente manera:

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

El código anterior es mucho más compacto, más fácil de leer y de escribir y sigue funcionando correctamente aunque se modifique el valor del atributo id del <div>.

9.2.2.3. Manejadores de eventos como funciones externas

La definición de los manejadores de eventos en los atributos XHTML es el método más sencillo pero menos aconsejable de 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.

Si se realizan aplicaciones complejas, como por ejemplo la validación de un formulario, es aconsejable agrupar todo el código JavaScript en una función externa y llamar a esta función desde el elemento XHTML.

Siguiendo con el ejemplo anterior que muestra un mensaje al pinchar sobre un botón:

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

Utilizando funciones externas se puede transformar en:

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

Esta técnica consiste en extraer todas las instrucciones de JavaScript y agruparlas en una función externa. Una vez definida la función, en el atributo del elemento XHTML se incluye el nombre de la función, para indicar que es la función que se ejecuta cuando se produce el evento.

La llamada a la función se realiza de la forma habitual, indicando su nombre seguido de los paréntesis y de forma opcional, incluyendo todos los argumentos y parámetros que se necesiten.

El principal inconveniente de este método es que en las funciones externas no se puede seguir utilizando la variablethis y por tanto, es necesario pasar esta variable como parámetro a la función:

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="width:150px; height:60px; border:thin solid silver" onmouseover="resalta(this)" onmouseout="resalta(this)">
  Sección de contenidos...
</div>

En el ejemplo anterior, la función externa es llamada con el parámetro this, que dentro de la función se denominaelemento. La complejidad del ejemplo se produce sobre todo 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 black, Internet Explorer lo almacena como black black black black y Opera almacena su representación hexadecimal #000000.

9.2.2.4. Manejadores de eventos semánticos

Los métodos que se han visto para añadir manejadores de eventos (como atributos XHTML y como funciones externas) tienen un grave inconveniente: “ensucian” el código XHTML de la página.

Como es conocido, una de las buenas prácticas básicas en el diseño de páginas y aplicaciones web es la separación de los contenidos (XHTML) y su aspecto o presentación (CSS). Siempre que sea posible, también se recomienda separar los contenidos (XHTML) y su comportamiento o programación (JavaScript).

Mezclar el código JavaScript con los elementos XHTML solamente contribuye a complicar el código fuente de la página, a dificultar la modificación y mantenimiento de la página y a reducir la semántica del documento final producido.

Afortunadamente, existe un método alternativo para definir los manejadores de eventos de JavaScript. Esta técnica es una evolución del método de las funciones externas, ya que se basa en utilizar las propiedades DOM de los elementos XHTML para asignar todas las funciones externas que actúan de manejadores de eventos. Así, el siguiente ejemplo:

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

Se puede transformar en:

// Función externa
function muestraMensaje() {
  alert('Gracias por pinchar');
}
 
// Asignar la función externa al elemento
document.getElementById("pinchable").onclick = muestraMensaje;
 
// Elemento XHTML
<input id="pinchable" type="button" value="Pinchame y verás" />

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 externa al evento correspondiente en el elemento deseado.

El último paso es la clave de esta técnica. En primer lugar, se obtiene el elemento al que se desea asociar la función externa:

document.getElementById("pinchable");

A continuación, se utiliza una propiedad del elemento con el mismo nombre que el evento que se quiere manejar. En este caso, la propiedad es onclick:

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

Por último, se asigna la función externa mediante su nombre sin paréntesis. 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 después del nombre de la función, en realidad se está ejecutando la función y guardando el valor devuelto por la función en la propiedad onclick de elemento.

// Asignar una función externa a un evento de un elemento
document.getElementById("pinchable").onclick = muestraMensaje;
 
// Ejecutar una función y guardar su resultado en una propiedad de un elemento
document.getElementById("pinchable").onclick = muestraMensaje();

La gran ventaja de este método es que el código XHTML resultante es muy “limpio”, ya que no se mezcla con el código JavaScript. Además, dentro de las funciones externas asignadas sí que se puede utilizar la variable this para referirse al elemento que provoca el evento.

El único inconveniente de este método es que la página se debe cargar completamente antes de que se puedan utilizar las funciones DOM que asignan los manejadores a los elementos XHTML. 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 eventoonload:

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

La técnica anterior utiliza el concepto de funciones anónimas, que no se va a estudiar, pero que permite crear un código compacto y muy sencillo. Para asegurarse que un código JavaScript va a ejecutarse después de que la página se haya cargado completamente, sólo es necesario incluir esas instrucciones entre los símbolos { y }:

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

En el siguiente ejemplo, se añaden eventos a los elementos de tipo input=text de un formulario complejo:

function resalta() {
  // Código JavaScript
}
 
window.onload = function() {
  var formulario = document.getElementById("formulario");
  var camposInput = formulario.getElementsByTagName("input");
 
  for(var i=0; i<camposInput.length; i++) {
    if(camposInput[i].type == "text") {
      camposInput[i].onclick = resalta;
    }
  }
}

Ejercicio 14

A partir de la página web proporcionada, 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
  4. Cuando una sección se oculte, debe cambiar el mensaje del enlace asociado (pista: propiedad innerHTML)
 

10. Obteniendo información del evento (objeto event)

Normalmente, los manejadores de eventos requieren información adicional para procesar sus tareas. Si una función por ejemplo se encarga de procesar el evento onclick, quizás necesite saber en que posición estaba el ratón en el momento de pinchar el botón.

No obstante, el caso más habitual en el que es necesario conocer información adicional sobre el evento es el de los eventos asociados al teclado. Normalmente, es muy importante conocer la tecla que se ha pulsado, por ejemplo para diferenciar las teclas normales de las teclas especiales (ENTER, tabulador, Alt, Ctrl., etc.).

JavaScript permite obtener información sobre el ratón y el teclado mediante un objeto especial llamado event. Desafortunadamente, los diferentes navegadores presentan diferencias muy notables en el tratamiento de la información sobre los eventos.

La principal diferencia reside en la forma en la que se obtiene el objeto event. Internet Explorer considera que este objeto forma parte del objeto window y el resto de navegadores lo consideran como el único argumento que tienen las funciones manejadoras de eventos.

Aunque es un comportamiento que resulta muy extraño al principio, todos los navegadores modernos excepto Internet Explorer crean mágicamente y de forma automática un argumento que se pasa a la función manejadora, por lo que no es necesario incluirlo en la llamada a la función manejadora. De esta forma, para utilizar este “argumento mágico”, sólo es necesario asignarle un nombre, ya que los navegadores lo crean automáticamente.

En resumen, en los navegadores tipo Internet Explorer, el objeto event se obtiene directamente mediante:

var evento = window.event;

Por otra parte, en el resto de navegadores, el objeto event se obtiene mágicamente a partir del argumento que el navegador crea automáticamente:

function manejadorEventos(elEvento) {
  var evento = elEvento;
}

Si se quiere programar una aplicación que funcione correctamente en todos los navegadores, es necesario obtener el objeto event de forma correcta según cada navegador. El siguiente código muestra la forma correcta de obtener el objeto event en cualquier navegador:

function manejadorEventos(elEvento) {
  var evento = elEvento || window.event;
}

Una vez obtenido el objeto event, ya se puede acceder a toda la información relacionada con el evento, que depende del tipo de evento producido.

10.1. Información sobre el evento

La propiedad type indica el tipo de evento producido, lo que es útil cuando una misma función se utiliza para manejar varios eventos:

var tipo = evento.type;

La propiedad type devuelve el tipo de evento producido, que es igual al nombre del evento pero sin el prefijo on.

Mediante esta propiedad, se puede rehacer de forma más sencilla el ejemplo anterior en el que se resaltaba una sección de contenidos al pasar el ratón por encima:

function resalta(elEvento) {
  var evento = elEvento || window.event;
  switch(evento.type) {
    case 'mouseover':
      this.style.borderColor = 'black';
      break;
    case 'mouseout':
      this.style.borderColor = 'silver';
      break;
  }
}
 
window.onload = function() {
  document.getElementById("seccion").onmouseover = resalta;
  document.getElementById("seccion").onmouseout = resalta;
}
 
<div id="seccion" style="width:150px; height:60px; border:thin solid silver">
  Sección de contenidos...
</div>

10.2. Información sobre los eventos de teclado

De todos los eventos disponibles en JavaScript, los eventos relacionados con el teclado son los más incompatibles entre diferentes navegadores y por tanto, los más difíciles de manejar. En primer lugar, existen muchas diferencias entre los navegadores, los teclados y los sistemas operativos de los usuarios, principalmente debido a las diferencias entre idiomas.

Además, existen tres eventos diferentes para las pulsaciones de las teclas (onkeyup, onkeypress y onkeydown). Por último, existen dos tipos de teclas: las teclas normales (como letras, números y símbolos normales) y las teclasespeciales (como ENTER, Alt, Shift, etc.)

Cuando un usuario pulsa una tecla normal, se producen tres eventos seguidos y en este orden: onkeydown, onkeypress yonkeyup. El evento onkeydown se corresponde con el hecho de pulsar una tecla y no soltarla; el evento onkeypress es la propia pulsación de la tecla y el evento onkeyup hace referencia al hecho de soltar una tecla que estaba pulsada.

La forma más sencilla de obtener la información sobre la tecla que se ha pulsado es mediante el evento onkeypress. La información que proporcionan los eventos onkeydown y onkeyup se puede considerar como más técnica, ya que devuelven el código interno de cada tecla y no el carácter que se ha pulsado.

A continuación se incluye una lista con todas las propiedades diferentes de todos los eventos de teclado tanto en Internet Explorer como en el resto de navegadores:

  • Evento keydown:
    • Mismo comportamiento en todos los navegadores:
      • Propiedad keyCode: código interno de la tecla
      • Propiedad charCode: no definido
  • Evento keypress:
    • Internet Explorer:
      • Propiedad keyCode: el código del carácter de la tecla que se ha pulsado
      • Propiedad charCode: no definido
    • Resto de navegadores:
      • Propiedad keyCode: para las teclas normales, no definido. Para las teclas especiales, el código interno de la tecla.
      • Propiedad charCode: para las teclas normales, el código del carácter de la tecla que se ha pulsado. Para las teclas especiales, 0.
  • Evento keyup:
    • Mismo comportamiento en todos los navegadores:
      • Propiedad keyCode: código interno de la tecla
      • Propiedad charCode: no definido

Para convertir el código de un carácter (no confundir con el código interno) al carácter que representa la tecla que se ha pulsado, se utiliza la función String.fromCharCode().

A continuación se incluye un script que muestra toda la información sobre los tres eventos de teclado:

window.onload = function() {
  document.onkeyup = muestraInformacion;
  document.onkeypress = muestraInformacion;
  document.onkeydown = muestraInformacion;
}
 
function muestraInformacion(elEvento) {
  var evento = window.event || elEvento;
 
  var mensaje = "Tipo de evento: " + evento.type + "<br>" +
                "Propiedad keyCode: " + evento.keyCode + "<br>" +
                "Propiedad charCode: " + evento.charCode + "<br>" +
                "Carácter pulsado: " + String.fromCharCode(evento.charCode);
 
  info.innerHTML += "<br>--------------------------------------<br>" + mensaje
}
 
...
 
<div id="info"></div>

Al pulsar la tecla a en el navegador Firefox, se muestra la siguiente sucesión de eventos:

--------------------------------------
Tipo de evento: keydown
Propiedad keyCode: 65
Propiedad charCode: 0
## Carácter pulsado: ?Tipo de evento: keypress
Propiedad keyCode: 0
Propiedad charCode: 97
## Carácter pulsado: aTipo de evento: keyup
Propiedad keyCode: 65
Propiedad charCode: 0
Carácter pulsado: ?

Al pulsar la tecla A (la misma tecla, pero habiendo activado previamente las mayúsculas) se muestra la siguiente sucesión de eventos en el navegador Firefox:

--------------------------------------
Tipo de evento: keydown
Propiedad keyCode: 65
Propiedad charCode: 0
## Carácter pulsado: ?Tipo de evento: keypress
Propiedad keyCode: 0
Propiedad charCode: 65
## Carácter pulsado: ATipo de evento: keyup
Propiedad keyCode: 65
Propiedad charCode: 0
Carácter pulsado: ?

En los eventos keydown y keyup, la propiedad keyCode sigue valiendo lo mismo en los dos casos. El motivo es quekeyCode almacena el código interno de la tecla, por lo que si se pulsa la misma tecla, se obtiene el mismo código, independientemente de que una misma tecla puede producir caracteres diferentes (por ejemplo mayúsculas y minúsculas).

En el evento keypress, el valor de la propiedad charCode varía, ya que el carácter a, no es el mismo que el carácter A. En este caso, el valor de charCode coincide con el código ASCII del carácter pulsado.

Siguiendo en el navegador Firefox, si ahora se pulsa una tecla especial, como por ejemplo el tabulador, se muestra la siguiente información:

--------------------------------------
Tipo de evento: keydown
Propiedad keyCode: 9
Propiedad charCode: 0
## Carácter pulsado: ?Tipo de evento: keypress
Propiedad keyCode: 9
Propiedad charCode: 0
## Carácter pulsado: ?Tipo de evento: keyup
Propiedad keyCode: 9
Propiedad charCode: 0
Carácter pulsado: ?

Las teclas especiales no disponen de la propiedad charCode, ya que sólamente se guarda el código interno de la tecla pulsada en la propiedad keyCode, en este caso el código 9. Si se pulsa la tecla Enter, se obtiene el código 13, la tecla de la flecha superior produce el código 38, etc. No obstante, dependiendo del teclado utilizado para pulsar las teclas y dependiendo de la disposición de las teclas en función del idioma del teclado, estos códigos podrían variar.

A continuación se muestra el resultado de la ejecución del mismo ejemplo anterior en el navegador Internet Explorer. Al pulsar la tecla a, se obtiene la siguiente información:

--------------------------------------
Tipo de evento: keydown
Propiedad keyCode: 65
Propiedad charCode: undefined
## Carácter pulsado: Tipo de evento: keypress
Propiedad keyCode: 97
Propiedad charCode: undefined
## Carácter pulsado: Tipo de evento: keyup
Propiedad keyCode: 65
Propiedad charCode: undefined
Carácter pulsado:

La propiedad keyCode en el evento keypress contiene el código ASCII del carácter de la tecla, por lo que se puede obtener directamente el carácter mediante String.fromCharCode(keyCode).

Si se pulsa la tecla A, la información mostrada es idéntica a la anterior, salvo que el código que muestra el eventokeypress cambia por 65, que es el código ASCII de la tecla A:

--------------------------------------
Tipo de evento: keydown
Propiedad keyCode: 65
Propiedad charCode: undefined
## Carácter pulsado: Tipo de evento: keypress
Propiedad keyCode: 65
Propiedad charCode: undefined
## Carácter pulsado: Tipo de evento: keyup
Propiedad keyCode: 65
Propiedad charCode: undefined
Carácter pulsado:

Al pulsar una tecla especial como el tabulador, Internet Explorer muestra la siguiente información:

--------------------------------------
Tipo de evento: keydown
Propiedad keyCode: 9
Propiedad charCode: undefined
Carácter pulsado:

Los códigos mostrados para las teclas especiales coinciden con los de Firefox y el resto de navegadores, pero recuerda que pueden variar en función del teclado que se utiliza y en función de la disposición de las teclas para cada idioma.

Por último, las propiedades altKey, ctrlKey y shiftKey almacenan un valor booleano que indica si alguna de esas teclas estaba pulsada al producirse el evento del teclado. Sorprendentemente, estas tres propiedades funcionan de la misma forma en todos los navegadores:

if(evento.altKey) {
  alert('Estaba pulsada la tecla ALT');
}

A continuación se muestra el caso en el que se pulsa la tecla Shift y sin soltarla, se pulsa sobre la tecla que contiene el número 2 (en este caso, se refiere a la tecla que se encuentra en la parte superior del teclado y por tanto, no se refiere a la que se encuentra en el teclado numérico). Tanto Internet Explorer como Firefox muestran la misma secuencia de eventos:

--------------------------------------
Tipo de evento: keydown
Propiedad keyCode: 16
Propiedad charCode: 0
## Carácter pulsado: ?Tipo de evento: keydown
Propiedad keyCode: 50
Propiedad charCode: 0
## Carácter pulsado: ?Tipo de evento: keypress
Propiedad keyCode: 0
Propiedad charCode: 34
## Carácter pulsado: "Tipo de evento: keyup
Propiedad keyCode: 50
Propiedad charCode: 0
## Carácter pulsado: ?Tipo de evento: keyup
Propiedad keyCode: 16
Propiedad charCode: 0
Carácter pulsado: ?

El evento keypress es el único que permite obtener el carácter realmente pulsado, ya que al pulsar sobre la tecla 2habiendo pulsado la tecla Shift previamente, se obtiene el carácter ", que es precisamente el que muestra el eventokeypress.

El siguiente código de JavaScript permite obtener de forma correcta en cualquier navegador el carácter correspondiente a la tecla pulsada:

function manejador(elEvento) {
  var evento = elEvento || window.event;
  var caracter = evento.charCode || evento.keyCode;
  alert("El carácter pulsado es: " + String.fromCharCode(caracter));
}
 
document.onkeypress = manejador;

10.3. Información sobre los eventos de ratón

La información más relevante sobre los eventos relacionados con el ratón es la de las coordenadas de la posición del puntero del ratón. Aunque el origen de las coordenadas siempre se encuentra en la esquina superior izquierda, el punto que se toma como referencia de las coordenadas puede variar.

De esta forma, es posible obtener la posición del ratón respecto de la pantalla del ordenador, respecto de la ventana del navegador y respecto de la propia página HTML (que se utiliza cuando el usuario ha hecho scroll sobre la página). Las coordenadas más sencillas son las que se refieren a la posición del puntero respecto de la ventana del navegador, que se obtienen mediante las propiedades clientX y clientY:

function muestraInformacion(elEvento) {
  var evento = elEvento || window.event;
  var coordenadaX = evento.clientX;
  var coordenadaY = evento.clientY;
  alert("Has pulsado el ratón en la posición: " + coordenadaX + ", " + coordenadaY);
}
 
document.onclick = muestraInformacion;

Las coordenadas de la posición del puntero del ratón respecto de la pantalla completa del ordenador del usuario se obtienen de la misma forma, mediante las propiedades screenX y screenY:

var coordenadaX = evento.screenX;
var coordenadaY = evento.screenY;

En muchas ocasiones, es necesario obtener otro par de coordenadas diferentes: las que corresponden a la posición del ratón respecto del origen de la página. Estas coordenadas no siempre coinciden con las coordenadas respecto del origen de la ventana del navegador, ya que el usuario puede hacer scroll sobre la página web. Internet Explorer no proporciona estas coordenadas de forma directa, mientras que el resto de navegadores sí que lo hacen. De esta forma, es necesario detectar si el navegador es de tipo Internet Explorer y en caso afirmativo realizar un cálculo sencillo:

// Detectar si el navegador es Internet Explorer
var ie = navigator.userAgent.toLowerCase().indexOf('msie')!=-1;
 
if(ie) {
  coordenadaX = evento.clientX + document.body.scrollLeft;
  coordenadaY = evento.clientY + document.body.scrollTop;
}
else {
  coordenadaX = evento.pageX;
  coordenadaY = evento.pageY;
}
alert("Has pulsado el ratón en la posición: " + coordenadaX + ", " + coordenadaY + " respecto de la página web");

La variable ie vale true si el navegador en el que se ejecuta el script es de tipo Internet Explorer (cualquier versión) y vale false en otro caso. Para el resto de navegadores, las coordenadas respecto del origen de la página se obtienen mediante las propiedades pageX y pageY. En el caso de Internet Explorer, se obtienen sumando la posición respecto de la ventana del navegador (clientX, clientY) y el desplazamiento que ha sufrido la página (document.body.scrollLeft,document.body.scrollTop).

Capítulo 11. Formularios

descarga (345)images (68)

11.1. Propiedades básicas de formularios y elementos

JavaScript dispone de numerosas propiedades y funciones que facilitan la programación de aplicaciones que manejan formularios. En primer lugar, cuando se carga una página web, el navegador crea automáticamente un array llamadoforms y que contiene la referencia a todos los formularios de la página.

Para acceder al array forms, se utiliza el objeto document, por lo que document.forms es el array que contiene todos los formularios de la página. Como se trata de un array, el acceso a cada formulario se realiza con la misma sintaxis de los arrays. La siguiente instrucción accede al primer formulario de la página:

document.forms[0];

Además del array de formularios, el navegador crea automáticamente un array llamado elements por cada uno de los formularios de la página. Cada array elements contiene la referencia a todos los elementos (cuadros de texto, botones, listas desplegables, etc.) de ese formulario. Utilizando la sintaxis de los arrays, la siguiente instrucción obtiene el primer elemento del primer formulario de la página:

document.forms[0].elements[0];

La sintaxis de los arrays no siempre es tan concisa. El siguiente ejemplo muestra cómo obtener directamente el último elemento del primer formulario de la página:

document.forms[0].elements[document.forms[0].elements.length-1];

Aunque esta forma de acceder a los formularios es rápida y sencilla, tiene un inconveniente muy grave. ¿Qué sucede si cambia el diseño de la página y en el código HTML se cambia el orden de los formularios originales o se añaden nuevos formularios? El problema es que “el primer formulario de la página” ahora podría ser otro formulario diferente al que espera la aplicación.

En un entorno tan cambiante como el diseño web, es muy difícil confiar en que el orden de los formularios se mantenga estable en una página web. Por este motivo, siempre debería evitarse el acceso a los formularios de una página mediante el array document.forms.

Una forma de evitar los problemas del método anterior consiste en acceder a los formularios de una página a través de su nombre (atributo name) o a través de su atributo id. El objeto document permite acceder directamente a cualquier formulario mediante su atributo name:

var formularioPrincipal = document.formulario;
var formularioSecundario = document.otro_formulario;
 
<form name="formulario" >
  ...
</form>
 
<form name="otro_formulario" >
  ...
</form>

Accediendo de esta forma a los formularios de la página, el script funciona correctamente aunque se reordenen los formularios o se añadan nuevos formularios a la página. Los elementos de los formularios también se pueden acceder directamente mediante su atributo name:

var formularioPrincipal = document.formulario;
var primerElemento = document.formulario.elemento;
 
<form name="formulario">
  <input type="text" name="elemento" />
</form>

Obviamente, también se puede acceder a los formularios y a sus elementos utilizando las funciones DOM de acceso directo a los nodos. El siguiente ejemplo utiliza la habitual función document.getElementById() para acceder de forma directa a un formulario y a uno de sus elementos:

var formularioPrincipal = document.getElementById("formulario");
var primerElemento = document.getElementById("elemento");
 
<form name="formulario" id="formulario" >
  <input type="text" name="elemento" id="elemento" />
</form>

Independientemente del método utilizado para obtener la referencia a un elemento de formulario, cada elemento dispone de las siguientes propiedades útiles para el desarrollo de las aplicaciones:

  • type: indica el tipo de elemento que se trata. Para los elementos de tipo <input> (text, button, checkbox, etc.) coincide con el valor de su atributo type. Para las listas desplegables normales (elemento <select>) su valor esselect-one, lo que permite diferenciarlas de las listas que permiten seleccionar varios elementos a la vez y cuyo tipo es select-multiple. Por último, en los elementos de tipo <textarea>, el valor de type es textarea.
  • form: es una referencia directa al formulario al que pertenece el elemento. Así, para acceder al formulario de un elemento, se puede utilizar document.getElementById("id_del_elemento").form
  • name: obtiene el valor del atributo name de XHTML. Solamente se puede leer su valor, por lo que no se puede modificar.
  • value: permite leer y modificar el valor del atributo value de XHTML. Para los campos de texto (<input type="text"> y <textarea>) obtiene el texto que ha escrito el usuario. Para los botones obtiene el texto que se muestra en el botón. Para los elementos checkbox y radiobutton no es muy útil, como se verá más adelante

Por último, los eventos más utilizados en el manejo de los formularios son los siguientes:

  • onclick: evento que se produce cuando se pincha con el ratón sobre un elemento. Normalmente se utiliza con cualquiera de los tipos de botones que permite definir XHTML (<input type="button">, <input type="submit">,<input type="image">).
  • onchange: evento que se produce cuando el usuario cambia el valor de un elemento de texto (<input type="text">o <textarea>). También se produce cuando el usuario selecciona una opción en una lista desplegable (<select>). Sin embargo, el evento sólo se produce si después de realizar el cambio, el usuario pasa al siguiente campo del formulario, lo que técnicamente se conoce como que “el otro campo de formulario ha perdido el foco”.
  • onfocus: evento que se produce cuando el usuario selecciona un elemento del formulario.
  • onblur: evento complementario de onfocus, ya que se produce cuando el usuario ha deseleccionado un elemento por haber seleccionado otro elemento del formulario. Técnicamente, se dice que el elemento anterior “ha perdido el foco”.
  • 11.2. Utilidades básicas para formularios

    11.2.1. Obtener el valor de los campos de formulario

    La mayoría de técnicas JavaScript relacionadas con los formularios requieren leer y/o modificar el valor de los campos del formulario. Por tanto, a continuación se muestra cómo obtener el valor de los campos de formulario más utilizados.

    11.2.1.1. Cuadro de texto y textarea

    El valor del texto mostrado por estos elementos se obtiene y se establece directamente mediante la propiedad value.

    <input type="text" id="texto" />
    var valor = document.getElementById("texto").value;
     
    <textarea id="parrafo"></textarea>
    var valor = document.getElementById("parrafo").value;

    11.2.1.2. Radiobutton

    Cuando se dispone de un grupo de radiobuttons, generalmente no se quiere obtener el valor del atributo value de alguno de ellos, sino que lo importante es conocer cuál de todos los radiobuttons se ha seleccionado. La propiedadchecked devuelve true para el radiobutton seleccionado y false en cualquier otro caso. Si por ejemplo se dispone del siguiente grupo de radiobuttons:

    <input type="radio" value="si" name="pregunta" id="pregunta_si"/> SI
    <input type="radio" value="no" name="pregunta" id="pregunta_no"/> NO
    <input type="radio" value="nsnc" name="pregunta" id="pregunta_nsnc"/> NS/NC

    El siguiente código permite determinar si cada radiobutton ha sido seleccionado o no:

    var elementos = document.getElementsByName("pregunta");
     
    for(var i=0; i<elementos.length; i++) {
      alert(" Elemento: " + elementos[i].value + "\n Seleccionado: " + elementos[i].checked);
    }

    11.2.1.3. Checkbox

    Los elementos de tipo checkbox son muy similares a los radiobutton, salvo que en este caso se debe comprobar cadacheckbox de forma independiente del resto. El motivo es que los grupos de radiobutton son mutuamente excluyentes y sólo se puede seleccionar uno de ellos cada vez. Por su parte, los checkbox se pueden seleccionar de forma independiente respecto de los demás.

    Si se dispone de los siguientes checkbox:

    <input type="checkbox" value="condiciones" name="condiciones" id="condiciones"/> He leído y acepto las condiciones
    <input type="checkbox" value="privacidad" name="privacidad" id="privacidad"/> He leído la política de privacidad

    Utilizando la propiedad checked, es posible comprobar si cada checkbox ha sido seleccionado:

    var elemento = document.getElementById("condiciones");
    alert(" Elemento: " + elemento.value + "\n Seleccionado: " + elemento.checked);
     
    elemento = document.getElementById("privacidad");
    alert(" Elemento: " + elemento.value + "\n Seleccionado: " + elemento.checked);

    11.2.1.4. Select

    Las listas desplegables (<select>) son los elementos en los que es más difícil obtener su valor. Si se dispone de una lista desplegable como la siguiente:

    <select id="opciones" name="opciones">
      <option value="1">Primer valor</option>
      <option value="2">Segundo valor</option>
      <option value="3">Tercer valor</option>
      <option value="4">Cuarto valor</option>
    </select>

    En general, lo que se requiere es obtener el valor del atributo value de la opción (<option>) seleccionada por el usuario. Obtener este valor no es sencillo, ya que se deben realizar una serie de pasos. Además, para obtener el valor seleccionado, deben utilizarse las siguientes propiedades:

    • options, es un array creado automáticamente por el navegador para cada lista desplegable y que contiene la referencia a todas las opciones de esa lista. De esta forma, la primera opción de una lista se puede obtener mediante document.getElementById("id_de_la_lista").options[0].
    • selectedIndex, cuando el usuario selecciona una opción, el navegador actualiza automáticamente el valor de esta propiedad, que guarda el índice de la opción seleccionada. El índice hace referencia al array options creado automáticamente por el navegador para cada lista.
    // Obtener la referencia a la lista
    var lista = document.getElementById("opciones");
     
    // Obtener el índice de la opción que se ha seleccionado
    var indiceSeleccionado = lista.selectedIndex;
    // Con el índice y el array "options", obtener la opción seleccionada
    var opcionSeleccionada = lista.options[indiceSeleccionado];
     
    // Obtener el valor y el texto de la opción seleccionada
    var textoSeleccionado = opcionSeleccionada.text;
    var valorSeleccionado = opcionSeleccionada.value;
     
    alert("Opción seleccionada: " + textoSeleccionado + "\n Valor de la opción: " + valorSeleccionado);

    Como se ha visto, para obtener el valor del atributo value correspondiente a la opción seleccionada por el usuario, es necesario realizar varios pasos. No obstante, normalmente se abrevian todos los pasos necesarios en una única instrucción:

    var lista = document.getElementById("opciones");
     
    // Obtener el valor de la opción seleccionada
    var valorSeleccionado = lista.options[lista.selectedIndex].value;
     
    // Obtener el texto que muestra la opción seleccionada
    var valorSeleccionado = lista.options[lista.selectedIndex].text;

    Lo más importante es no confundir el valor de la propiedad selectedIndex con el valor correspondiente a la propiedadvalue de la opción seleccionada. En el ejemplo anterior, la primera opción tiene un value igual a 1. Sin embargo, si se selecciona esta opción, el valor de selectedIndex será 0, ya que es la primera opción del array options (y los arrays empiezan a contar los elementos en el número 0).

    11.2.2. Establecer el foco en un elemento

    En programación, cuando un elemento está seleccionado y se puede escribir directamente en el o se puede modificar alguna de sus propiedades, se dice que tiene el foco del programa.

    Si un cuadro de texto de un formulario tiene el foco, el usuario puede escribir directamente en el sin necesidad de pinchar previamente con el ratón en el interior del cuadro. Igualmente, si una lista desplegable tiene el foco, el usuario puede seleccionar una opción directamente subiendo y bajando con las flechas del teclado.

    Al pulsar repetidamente la tecla TABULADOR sobre una página web, los diferentes elementos (enlaces, imágenes, campos de formulario, etc.) van obteniendo el foco del navegador (el elemento seleccionado cada vez suele mostrar un pequeño borde punteado).

    Si en una página web el formulario es el elemento más importante, como por ejemplo en una página de búsqueda o en una página con un formulario para registrarse, se considera una buena práctica de usabilidad el asignar automáticamente el foco al primer elemento del formulario cuando se carga la página.

    Para asignar el foco a un elemento de XHTML, se utiliza la función focus(). El siguiente ejemplo asigna el foco a un elemento de formulario cuyo atributo id es igual a primero:

    document.getElementById("primero").focus();
     
    <form id="formulario" action="#">
      <input type="text" id="primero" />
    </form>

    Ampliando el ejemplo anterior, se puede asignar automáticamente el foco del programa al primer elemento del primer formulario de la página, independientemente del id del formulario y de los elementos:

    if(document.forms.length > 0) {
      if(document.forms[0].elements.length > 0) {
        document.forms[0].elements[0].focus();
      }
    }

    El código anterior comprueba que existe al menos un formulario en la página mediante el tamaño del array forms. Si su tamaño es mayor que 0, se utiliza este primer formulario. Empleando la misma técnica, se comprueba que el formulario tenga al menos un elemento (if(document.forms[0].elements.length > 0)). En caso afirmativo, se establece el foco del navegador en el primer elemento del primer formulario (document.forms[0].elements[0].focus();).

    Para que el ejemplo anterior sea completamente correcto, se debe añadir una comprobación adicional. El campo de formulario que se selecciona no debería ser de tipo hidden:

    if(document.forms.length > 0) {
      for(var i=0; i < document.forms[0].elements.length; i++) {
        var campo = document.forms[0].elements[i];
        if(campo.type != "hidden") {
          campo.focus();
          break;
        }
      }
    }

    11.2.3. Evitar el envío duplicado de un formulario

    Uno de los problemas habituales con el uso de formularios web es la posibilidad de que el usuario pulse dos veces seguidas sobre el botón “Enviar”. Si la conexión del usuario es demasiado lenta o la respuesta del servidor se hace esperar, el formulario original sigue mostrándose en el navegador y por ese motivo, el usuario tiene la tentación de volver a pinchar sobre el botón de “Enviar”.

    En la mayoría de los casos, el problema no es grave e incluso es posible controlarlo en el servidor, pero puede complicarse en formularios de aplicaciones importantes como las que implican transacciones económicas.

    Por este motivo, una buena práctica en el diseño de aplicaciones web suele ser la de deshabilitar el botón de envío después de la primera pulsación. El siguiente ejemplo muestra el código necesario:

    <form id="formulario" action="#">
      ...
      <input type="button" value="Enviar" onclick="this.disabled=true; this.value=’Enviando...’; this.form.submit()" />
    </form>

    Cuando se pulsa sobre el botón de envío del formulario, se produce el evento onclick sobre el botón y por tanto, se ejecutan las instrucciones JavaScript contenidas en el atributo onclick:

    1. En primer lugar, se deshabilita el botón mediante la instrucción this.disabled = true;. Esta es la única instrucción necesaria si sólo se quiere deshabilitar un botón.
    2. A continuación, se cambia el mensaje que muestra el botón. Del original “Enviar” se pasa al más adecuado “Enviando…”
    3. Por último, se envía el formulario mediante la función submit() en la siguiente instrucción: this.form.submit()

    El botón del ejemplo anterior está definido mediante un botón de tipo <input type="button" />, ya que el código JavaScript mostrado no funciona correctamente con un botón de tipo <input type="submit" />. Si se utiliza un botón de tipo submit, el botón se deshabilita antes de enviar el formulario y por tanto el formulario acaba sin enviarse.

    11.2.4. Limitar el tamaño de caracteres de un textarea

    La carencia más importante de los campos de formulario de tipo textarea es la imposibilidad de limitar el máximo número de caracteres que se pueden introducir, de forma similar al atributo maxlength de los cuadros de texto normales.

    JavaScript permite añadir esta característica de forma muy sencilla. En primer lugar, hay que recordar que con algunos eventos (como onkeypress, onclick y onsubmit) se puede evitar su comportamiento normal si se devuelve el valor false.

    Evitar el comportamiento normal equivale a modificar completamente el comportamiento habitual del evento. Si por ejemplo se devuelve el valor false en el evento onkeypress, la tecla pulsada por el usuario no se tiene en cuenta. Si se devuelve false en el evento onclick de un elemento como un enlace, el navegador no carga la página indicada por el enlace.

    Si un evento devuelve el valor true, su comportamiento es el habitual:

    <textarea onkeypress="return true;"></textarea>

    En el textarea del ejemplo anterior, el usuario puede escribir cualquier carácter, ya que el evento onkeypress devuelvetrue y por tanto, su comportamiento es el normal y la tecla pulsada se transforma en un carácter dentro del textarea.

    Sin embargo, en el siguiente ejemplo:

    <textarea onkeypress="return false;"></textarea>

    Como el valor devuelto por el evento onkeypress es igual a false, el navegador no ejecuta el comportamiento por defecto del evento, es decir, la tecla presionada no se transforma en ningún carácter dentro del textarea. No importa las veces que se pulsen las teclas y no importa la tecla pulsada, ese textarea no permitirá escribir ningún carácter.

    Aprovechando esta característica, es sencillo limitar el número de caracteres que se pueden escribir en un elemento de tipo textarea: se comprueba si se ha llegado al máximo número de caracteres permitido y en caso afirmativo se evita el comportamiento habitual del evento y por tanto, los caracteres adicionales no se añaden al textarea:

    function limita(maximoCaracteres) {
      var elemento = document.getElementById("texto");
      if(elemento.value.length >= maximoCaracteres ) {
        return false;
      }
      else {
        return true;
      }
    }
     
    <textarea id="texto" onkeypress="return limita(100);"></textarea>

    En el ejemplo anterior, con cada tecla pulsada se compara el número total de caracteres del textarea con el máximo número de caracteres permitido. Si el número de caracteres es igual o mayor que el límite, se devuelve el valor false y por tanto, se evita el comportamiento por defecto de onkeypress y la tecla no se añade.

    11.2.5. Restringir los caracteres permitidos en un cuadro de texto

    En ocasiones, puede ser útil bloquear algunos caracteres determinados en un cuadro de texto. Si por ejemplo un cuadro de texto espera que se introduzca un número, puede ser interesante no permitir al usuario introducir ningún carácter que no sea numérico.

    Igualmente, en algunos casos puede ser útil impedir que el usuario introduzca números en un cuadro de texto. Utilizando el evento onkeypress y unas cuantas sentencias JavaScript, el problema se resuelve fácilmente:

    function permite(elEvento, permitidos) {
      // Variables que definen los caracteres permitidos
      var numeros = "0123456789";
      var caracteres = " abcdefghijklmnñopqrstuvwxyzABCDEFGHIJKLMNÑOPQRSTUVWXYZ";
      var numeros_caracteres = numeros + caracteres;
      var teclas_especiales = [8, 37, 39, 46];
      // 8 = BackSpace, 46 = Supr, 37 = flecha izquierda, 39 = flecha derecha
     
     
      // Seleccionar los caracteres a partir del parámetro de la función
      switch(permitidos) {
        case 'num':
          permitidos = numeros;
          break;
        case 'car':
          permitidos = caracteres;
          break;
        case 'num_car':
          permitidos = numeros_caracteres;
          break;
      }
     
      // Obtener la tecla pulsada 
      var evento = elEvento || window.event;
      var codigoCaracter = evento.charCode || evento.keyCode;
      var caracter = String.fromCharCode(codigoCaracter);
     
      // Comprobar si la tecla pulsada es alguna de las teclas especiales
      // (teclas de borrado y flechas horizontales)
      var tecla_especial = false;
      for(var i in teclas_especiales) {
        if(codigoCaracter == teclas_especiales[i]) {
          tecla_especial = true;
          break;
        }
      }
     
      // Comprobar si la tecla pulsada se encuentra en los caracteres permitidos
      // o si es una tecla especial
      return permitidos.indexOf(caracter) != -1 || tecla_especial;
    }
     
    // Sólo números
    <input type="text" id="texto" onkeypress="return permite(event, 'num')" />
     
    // Sólo letras
    <input type="text" id="texto" onkeypress="return permite(event, 'car')" />
     
    // Sólo letras o números
    <input type="text" id="texto" onkeypress="return permite(event, 'num_car')" />

    El funcionamiento del script anterior se basa en permitir o impedir el comportamiento habitual del evento onkeypress. Cuando se pulsa una tecla, se comprueba si el carácter de esa tecla se encuentra dentro de los caracteres permitidos para ese elemento <input>.

    Si el carácter se encuentra dentro de los caracteres permitidos, se devuelve true y por tanto el comportamiento deonkeypress es el habitual y la tecla se escribe. Si el carácter no se encuentra dentro de los caracteres permitidos, se devuelve false y por tanto se impide el comportamiento normal de onkeypress y la tecla no llega a escribirse en el input.

    Además, el script anterior siempre permite la pulsación de algunas teclas especiales. En concreto, las teclas BackSpacey Supr para borrar caracteres y las teclas Flecha Izquierda y Flecha Derecha para moverse en el cuadro de texto siempre se pueden pulsar independientemente del tipo de caracteres permitidos.

  • 12.3. Validación     images (69)

    La principal utilidad de JavaScript en el manejo de los formularios es la validación de los datos introducidos por los usuarios. Antes de enviar un formulario al servidor, se recomienda validar mediante JavaScript los datos insertados por el usuario. De esta forma, si el usuario ha cometido algún error al rellenar el formulario, se le puede notificar de forma instantánea, sin necesidad de esperar la respuesta del servidor.

    Notificar los errores de forma inmediata mediante JavaScript mejora la satisfacción del usuario con la aplicación (lo que técnicamente se conoce como “mejorar la experiencia de usuario”) y ayuda a reducir la carga de procesamiento en el servidor.

    Normalmente, la validación de un formulario consiste en llamar a una función de validación cuando el usuario pulsa sobre el botón de envío del formulario. En esta función, se comprueban si los valores que ha introducido el usuario cumplen las restricciones impuestas por la aplicación.

    Aunque existen tantas posibles comprobaciones como elementos de formulario diferentes, algunas comprobaciones son muy habituales: que se rellene un campo obligatorio, que se seleccione el valor de una lista desplegable, que la dirección de email indicada sea correcta, que la fecha introducida sea lógica, que se haya introducido un número donde así se requiere, etc.

    A continuación se muestra el código JavaScript básico necesario para incorporar la validación a un formulario:

    <form action="" method="" id="" name="" onsubmit="return validacion()">
      ...
    </form>

    Y el esquema de la función validacion() es el siguiente:

    function validacion() {
      if (condicion que debe cumplir el primer campo del formulario) {
        // Si no se cumple la condicion...
        alert('[ERROR] El campo debe tener un valor de...');
        return false;
      }
      else if (condicion que debe cumplir el segundo campo del formulario) {
        // Si no se cumple la condicion...
        alert('[ERROR] El campo debe tener un valor de...');
        return false;
      }
      ...
      else if (condicion que debe cumplir el último campo del formulario) {
        // Si no se cumple la condicion...
        alert('[ERROR] El campo debe tener un valor de...');
        return false;
      }
     
      // Si el script ha llegado a este punto, todas las condiciones
      // se han cumplido, por lo que se devuelve el valor true
      return true;
    }

    El funcionamiento de esta técnica de validación se basa en el comportamiento del evento onsubmit de JavaScript. Al igual que otros eventos como onclick y onkeypress, el evento 'onsubmit varía su comportamiento en función del valor que se devuelve.

    Así, si el evento onsubmit devuelve el valor true, el formulario se envía como lo haría normalmente. Sin embargo, si el evento onsubmit devuelve el valor false, el formulario no se envía. La clave de esta técnica consiste en comprobar todos y cada uno de los elementos del formulario. En cuando se encuentra un elemento incorrecto, se devuelve el valorfalse. Si no se encuentra ningún error, se devuelve el valor true.

    Por lo tanto, en primer lugar se define el evento onsubmit del formulario como:

    onsubmit="return validacion()"

    Como el código JavaScript devuelve el valor resultante de la función validacion(), el formulario solamente se enviará al servidor si esa función devuelve true. En el caso de que la función validacion() devuelva false, el formulario permanecerá sin enviarse.

    Dentro de la función validacion() se comprueban todas las condiciones impuestas por la aplicación. Cuando no se cumple una condición, se devuelve false y por tanto el formulario no se envía. Si se llega al final de la función, todas las condiciones se han cumplido correctamente, por lo que se devuelve true y el formulario se envía.

    La notificación de los errores cometidos depende del diseño de cada aplicación. En el código del ejemplo anterior simplemente se muestran mensajes mediante la función alert() indicando el error producido. Las aplicaciones web mejor diseñadas muestran cada mensaje de error al lado del elemento de formulario correspondiente y también suelen mostrar un mensaje principal indicando que el formulario contiene errores.

    Una vez definido el esquema de la función validacion(), se debe añadir a esta función el código correspondiente a todas las comprobaciones que se realizan sobre los elementos del formulario. A continuación, se muestran algunas de las validaciones más habituales de los campos de formulario.

    12.3.1. Validar un campo de texto obligatorio

    Se trata de forzar al usuario a introducir un valor en un cuadro de texto o textarea en los que sea obligatorio. La condición en JavaScript se puede indicar como:

    valor = document.getElementById("campo").value;
    if( valor == null || valor.length == 0 || /^\s+$/.test(valor) ) {
      return false;
    }

    Para que se de por completado un campo de texto obligatorio, se comprueba que el valor introducido sea válido, que el número de caracteres introducido sea mayor que cero y que no se hayan introducido sólo espacios en blanco.

    La palabra reservada null es un valor especial que se utiliza para indicar “ningún valor”. Si el valor de una variable esnull, la variable no contiene ningún valor de tipo objeto, array, numérico, cadena de texto o booleano.

    La segunda parte de la condición obliga a que el texto introducido tenga una longitud superior a cero caracteres, esto es, que no sea un texto vacío.

    Por último, la tercera parte de la condición (/^\s+$/.test(valor)) obliga a que el valor introducido por el usuario no sólo esté formado por espacios en blanco. Esta comprobación se basa en el uso de “expresiones regulares”, un recurso habitual en cualquier lenguaje de programación pero que por su gran complejidad no se van a estudiar. Por lo tanto, sólo es necesario copiar literalmente esta condición, poniendo especial cuidado en no modificar ningún carácter de la expresión.

    12.3.2. Validar un campo de texto con valores numéricos

    Se trata de obligar al usuario a introducir un valor numérico en un cuadro de texto. La condición JavaScript consiste en:

    valor = document.getElementById("campo").value;
    if( isNaN(valor) ) {
      return false;
    }

    Si el contenido de la variable valor no es un número válido, no se cumple la condición. La ventaja de utilizar la función interna isNaN() es que simplifica las comprobaciones, ya que JavaScript se encarga de tener en cuenta los decimales, signos, etc.

    A continuación se muestran algunos resultados de la función isNaN():

    isNaN(3);          // false
    isNaN("3");        // false
    isNaN(3.3545);     // false
    isNaN(32323.345);  // false
    isNaN(+23.2);      // false
    isNaN("-23.2");    // false
    isNaN("23a");      // true
    isNaN("23.43.54"); // true

    12.3.3. Validar que se ha seleccionado una opción de una lista

    Se trata de obligar al usuario a seleccionar un elemento de una lista desplegable. El siguiente código JavaScript permite conseguirlo:

    indice = document.getElementById("opciones").selectedIndex;
    if( indice == null || indice == 0 ) {
      return false;
    }
     
    <select id="opciones" name="opciones">
      <option value="">- Selecciona un valor -</option>
      <option value="1">Primer valor</option>
      <option value="2">Segundo valor</option>
      <option value="3">Tercer valor</option>
    </select>

    A partir de la propiedad selectedIndex, se comprueba si el índice de la opción seleccionada es válido y además es distinto de cero. La primera opción de la lista (- Selecciona un valor –) no es válida, por lo que no se permite el valor 0para esta propiedad selectedIndex.

    12.3.4. Validar una dirección de email

    Se trata de obligar al usuario a introducir una dirección de email con un formato válido. Por tanto, lo que se comprueba es que la dirección parezca válida, ya que no se comprueba si se trata de una cuenta de correo electrónico real y operativa. La condición JavaScript consiste en:

    valor = document.getElementById("campo").value;
    if( !(/\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)/.test(valor)) ) {
      return false;
    }

    La comprobación se realiza nuevamente mediante las expresiones regulares, ya que las direcciones de correo electrónico válidas pueden ser muy diferentes. Por otra parte, como el estándar que define el formato de las direcciones de correo electrónico es muy complejo, la expresión regular anterior es una simplificación. Aunque esta regla valida la mayoría de direcciones de correo electrónico utilizadas por los usuarios, no soporta todos los diferentes formatos válidos de email.

    12.3.5. Validar una fecha

    Las fechas suelen ser los campos de formulario más complicados de validar por la multitud de formas diferentes en las que se pueden introducir. El siguiente código asume que de alguna forma se ha obtenido el año, el mes y el día introducidos por el usuario:

    var ano = document.getElementById("ano").value;
    var mes = document.getElementById("mes").value;
    var dia = document.getElementById("dia").value;
     
    valor = new Date(ano, mes, dia);
     
    if( !isNaN(valor) ) {
      return false;
    }

    La función Date(ano, mes, dia) es una función interna de JavaScript que permite construir fechas a partir del año, el mes y el día de la fecha. Es muy importante tener en cuenta que el número de mes se indica de 0 a 11, siendo 0 el mes de Enero y 11 el mes de Diciembre. Los días del mes siguen una numeración diferente, ya que el mínimo permitido es 1y el máximo 31.

    La validación consiste en intentar construir una fecha con los datos proporcionados por el usuario. Si los datos del usuario no son correctos, la fecha no se puede construir correctamente y por tanto la validación del formulario no será correcta.

    12.3.6. Validar un número de DNI

    Se trata de comprobar que el número proporcionado por el usuario se corresponde con un número válido de Documento Nacional de Identidad o DNI. Aunque para cada país o región los requisitos del documento de identidad de las personas pueden variar, a continuación se muestra un ejemplo genérico fácilmente adaptable. La validación no sólo debe comprobar que el número esté formado por ocho cifras y una letra, sino que también es necesario comprobar que la letra indicada es correcta para el número introducido:

    valor = document.getElementById("campo").value;
    var letras = ['T', 'R', 'W', 'A', 'G', 'M', 'Y', 'F', 'P', 'D', 'X', 'B', 'N', 'J', 'Z', 'S', 'Q', 'V', 'H', 'L', 'C', 'K', 'E', 'T'];
     
    if( !(/^\d{8}[A-Z]$/.test(valor)) ) {
      return false;
    }
     
    if(valor.charAt(8) != letras[(valor.substring(0, 8))%23]) {
      return false;
    }

    La primera comprobación asegura que el formato del número introducido es el correcto, es decir, que está formado por 8 números seguidos y una letra. Si la letra está al principio de los números, la comprobación sería /^[A-Z]\d{8}$/. Si en vez de ocho números y una letra, se requieren diez números y dos letras, la comprobación sería /^\d{10}[A-Z]{2}$/ y así sucesivamente.

    La segunda comprobación aplica el algoritmo de cálculo de la letra del DNI y la compara con la letra proporcionada por el usuario. El algoritmo de cada documento de identificación es diferente, por lo que esta parte de la validación se debe adaptar convenientemente.

    12.3.7. Validar un número de teléfono

    Los números de teléfono pueden ser indicados de formas muy diferentes: con prefijo nacional, con prefijo internacional, agrupado por pares, separando los números con guiones, etc.

    El siguiente script considera que un número de teléfono está formado por nueve dígitos consecutivos y sin espacios ni guiones entre las cifras:

    valor = document.getElementById("campo").value;
    if( !(/^\d{9}$/.test(valor)) ) {
      return false;
    }

    Una vez más, la condición de JavaScript se basa en el uso de expresiones regulares, que comprueban si el valor indicado es una sucesión de nueve números consecutivos. A continuación se muestran otras expresiones regulares que se pueden utilizar para otros formatos de número de teléfono:

    Número Expresión regular Formato
    900900900 /^\d{9}$/ 9 cifras seguidas
    900-900-900 /^\d{3}-\d{3}-\d{3}$/ 9 cifras agrupadas de 3 en 3 y separadas por guiones
    900 900900 /^\d{3}\s\d{6}$/ 9 cifras, las 3 primeras separadas por un espacio
    900 90 09 00 /^\d{3}\s\d{2}\s\d{2}\s\d{2}$/ 9 cifras, las 3 primeras separadas por un espacio, las siguientes agrupadas de 2 en 2
    (900) 900900 /^\(\d{3}\)\s\d{6}$/ 9 cifras, las 3 primeras encerradas por paréntesis y un espacio de separación respecto del resto
    +34 900900900 /^\+\d{2,3}\s\d{9}$/ Prefijo internacional (+ seguido de 2 o 3 cifras), espacio en blanco y 9 cifras consecutivas

    12.3.8. Validar que un checkbox ha sido seleccionado

    Si un elemento de tipo checkbox se debe seleccionar de forma obligatoria, JavaScript permite comprobarlo de forma muy sencilla:

    elemento = document.getElementById("campo");
    if( !elemento.checked ) {
      return false;
    }

    Si se trata de comprobar que todos los checkbox del formulario han sido seleccionados, es más fácil utilizar un bucle:

    formulario = document.getElementById("formulario");
    for(var i=0; i<formulario.elements.length; i++) {
      var elemento = formulario.elements[i];
      if(elemento.type == "checkbox") {
        if(!elemento.checked) {
          return false;
        }
      }
    }

    12.3.9. Validar que un radiobutton ha sido seleccionado

    Aunque se trata de un caso similar al de los checkbox, la validación de los radiobutton presenta una diferencia importante: en general, la comprobación que se realiza es que el usuario haya seleccionado algún radiobutton de los que forman un determinado grupo. Mediante JavaScript, es sencillo determinar si se ha seleccionado algún radiobuttonde un grupo:

    opciones = document.getElementsByName("opciones");
     
    var seleccionado = false;
    for(var i=0; i<opciones.length; i++) {    
      if(opciones[i].checked) {
        seleccionado = true;
        break;
      }
    }
     
    if(!seleccionado) {
      return false;
    }

    El anterior ejemplo recorre todos los radiobutton que forman un grupo y comprueba elemento por elemento si ha sido seleccionado. Cuando se encuentra el primer radiobutton seleccionado, se sale del bucle y se indica que al menos uno ha sido seleccionado.

Capítulo 13. Otras utilidades.

  • 13.1. Relojes, contadores e intervalos de tiempo

    En ocasiones, algunas páginas web muestran un reloj con la hora actual. Si el reloj debe actualizarse cada segundo, no se puede mostrar la hora directamente en la página HTML generada por el servidor. En este caso, aunque existen alternativas realizadas con Java y con Flash, la forma más sencilla de hacerlo es mostrar la hora del ordenador del usuario mediante JavaScript.

    Para crear y mostrar un reloj con JavaScript, se debe utilizar el objeto interno Date() para crear fechas/horas y las utilidades que permiten definir contadores, para actualizar el reloj cada segundo.

    El objeto Date() es una utilidad que proporciona JavaScript para crear fechas y horas. Una vez creado un objeto de tipo fecha, es posible manipularlo para obtener información o realizar cálculos con las fechas. Para obtener la fecha y hora actuales, solamente es necesario crear un objeto Date() sin pasar ningún parámetro:

    var fechaHora = new Date();

    Utilizando el código anterior, se puede construir un reloj muy básico que no actualiza su contenido:

    var fechaHora = new Date();
    document.getElementById("reloj").innerHTML = fechaHora;
     
    <div id="reloj" />

    Cuando se carga la página, el ejemplo anterior mostraría un texto parecido al siguiente en el <div> reservado para el reloj:

    Mon May 04 2009 13:36:10 GMT+0200 (Hora de verano romance)

    Este primer reloj construido presenta muchas diferencias respecto al reloj que se quiere construir. En primer lugar, muestra más información de la necesaria. Además, su valor no se actualiza cada segundo, por lo que no es un reloj muy práctico.

    El objeto Date() proporciona unas funciones muy útiles para obtener información sobre la fecha y la hora. Concretamente, existen funciones que devuelven la hora, los minutos y los segundos:

    var fechaHora = new Date();
    var horas = fechaHora.getHours();
    var minutos = fechaHora.getMinutes();
    var segundos = fechaHora.getSeconds();
     
    document.getElementById("reloj").innerHTML = horas+':'+minutos+':'+segundos;
     
    <div id="reloj" />

    Utilizando las funciones getHours(), getMinutes() y getSeconds() del objeto Date, el reloj solamente muestra la información de la hora. El resultado del ejemplo anterior sería un reloj como el siguiente:

    20:9:21

    Si la hora, minuto o segundo son menores que 10, JavaScript no añade el 0 por delante, por lo que el resultado no es del todo satisfactorio. El siguiente código soluciona este problema añadiendo un 0 cuando sea necesario:

    var fechaHora = new Date();
    var horas = fechaHora.getHours();
    var minutos = fechaHora.getMinutes();
    var segundos = fechaHora.getSeconds();
     
    if(horas < 10) { horas = '0' + horas; }
    if(minutos < 10) { minutos = '0' + minutos; }
    if(segundos < 10) { segundos = '0' + segundos; }
     
    document.getElementById("reloj").innerHTML = horas+':'+minutos+':'+segundos;
     
    <div id="reloj" />

    Ahora el reloj muestra correctamente la hora:

    20:14:03

    Si se quiere mostrar el reloj con un formato de 12 horas en vez de 24, se puede utilizar el siguiente código:

    var fechaHora = new Date();
    var horas = fechaHora.getHours();
    var minutos = fechaHora.getMinutes();
    var segundos = fechaHora.getSeconds();
     
    var sufijo = ' am';
    if(horas > 12) {
      horas = horas - 12;
      sufijo = ' pm';
    }
     
    if(horas < 10) { horas = '0' + horas; }
    if(minutos < 10) { minutos = '0' + minutos; }
    if(segundos < 10) { segundos = '0' + segundos; }
     
    document.getElementById("reloj").innerHTML = horas+':'+minutos+':'+segundos+sufijo;
     
    <div id="reloj" />

    Utilizando el código anterior, el reloj ya no muestra la hora como 20:14:03, sino que la muestra en formato de 12 horas y con el sufijo adecuado:

    08:14:03 pm

    Para completar el reloj, sólo falta que se actualice su valor cada segundo. Para conseguirlo, se deben utilizar unas funciones especiales de JavaScript que permiten ejecutar determinadas instrucciones cuando ha transcurrido un determinado espacio de tiempo.

    La función setTimeout() permite ejecutar una función una vez que haya transcurrido un periodo de tiempo indicado. La definición de la función es:

    setTimeout(nombreFuncion, milisegundos);

    La función que se va a ejecutar se debe indicar mediante su nombre sin paréntesis y el tiempo que debe transcurrir hasta que se ejecute se indica en milisegundos. De esta forma, si se crea una función encargada de mostrar la hora del reloj y se denomina muestraReloj(), se puede indicar que se ejecute dentro de 1 segundo mediante el siguiente código:

    function muestraReloj() {
      var fechaHora = new Date();
      var horas = fechaHora.getHours();
      var minutos = fechaHora.getMinutes();
      var segundos = fechaHora.getSeconds();
     
      if(horas < 10) { horas = '0' + horas; }
      if(minutos < 10) { minutos = '0' + minutos; }
      if(segundos < 10) { segundos = '0' + segundos; }
     
      document.getElementById("reloj").innerHTML = horas+':'+minutos+':'+segundos;
    }
     
    setTimeout(muestraReloj, 1000);
     
    <div id="reloj" />

    No obstante, el código anterior simplemente muestra el contenido del reloj 1 segundo después de que se cargue la página, por lo que no es muy útil. Para ejecutar una función de forma periódica, se utiliza una función de JavaScript muy similar a setTimeout() que se denomina setInterval(). Su definición es:

    setInterval(nombreFuncion, milisegundos);

    La definición de esta función es idéntica a la función setTimeout(), salvo que en este caso, la función programada se ejecuta infinitas veces de forma periódica con un lapso de tiempo entre ejecuciones de tantos milisegundos como se hayan establecido.

    Así, para construir el reloj completo, se establece una ejecución periódica de la función muestraReloj() cada segundo:

    function muestraReloj() {
      var fechaHora = new Date();
      var horas = fechaHora.getHours();
      var minutos = fechaHora.getMinutes();
      var segundos = fechaHora.getSeconds();
     
      if(horas < 10) { horas = '0' + horas; }
      if(minutos < 10) { minutos = '0' + minutos; }
      if(segundos < 10) { segundos = '0' + segundos; }
     
      document.getElementById("reloj").innerHTML = horas+':'+minutos+':'+segundos;
    }
     
    window.onload = function() {
      setInterval(muestraReloj, 1000);
    }
     
    <div id="reloj" />

    Empleando el objeto Date y sus funciones, es posible construir “cuentras atrás”, es decir, relojes que muestran el tiempo que falta hasta que se produzca un evento. Además, las funciones setTimeout() y setInterval() pueden resultar muy útiles en otras técnicas de programación.

 

 
 
 
 

 

 

 


Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

w

Conectando a %s