che roga

Scripts sencillos para problemas complejos

Ver scripts simples - Click

ceo@misosguar.com.ar

El caso del usuario desconocido

Nos presentamos ante el usuario y le decimos: Por favor, dinos tu nombre. El usuario responde y recordamos la respuesta en una variable.

Pedimos información con una ventana de diálogo (prompt)

<script language='Javascript'>
	usuario=prompt('Cuál es tu nombre por favor');
</script>
Aparecerá una ventana pidiendo al usuario que complete su nombre. Al pulsar Aceptar quedará en la variable usuario el valor ingresado. Si el usuario cancela, quedará null como valor de la variable. Por eso es mejor controlar el valor de la variable para no usarla si es null.
if (null==usuario) { return; }
Es una buena costumbre de programación colocar el valor escalar a la izquierda de una comparación por igual, por si nos confundimos el símbolo == con el =. De esta manera el error será notado más rápidamente. Puede ser que el usuario pulse Aceptar sin haber ingresado nada, en ese caso la variable contiene un carácter nulo (diferente al valor null) que se puede representar como ''. Podemos preguntar por él con un if:
if (''==usuario) { return; }
O podemos preguntar si no es verdadero, ya que el valor null y el carácter nulo se consideran valores de falso en Javacript:
if (!usuario) { return; }

Pedimos información con un control de entrada (input)

Colocamos un control input de texto con un id para identificarlos. Luego con código Javascript tomamos su valor para usarlo.
<input type='text' id='usuario_entrada' onChange='guardarDato()'>
<script language='Javascript'>
	function guardarDato(){
		nombre_elemento= document.getElementById("usuario_entrada"); 
		nombre= nombre_elemento.value; 
		alert("Tu nombre es "+nombre)
	}
</script>
Usamos el evento onChange para saber en qué momento el usuario terminó de ingresar el dato. Usamos la función getElementById() para tomar un objeto que está identificado por el id y luego tomamos su valor con la propiedad value.

La función guardarDato() podría tomar parámetros para ser más general y así servir para más tareas que tomar el nombre o el valor de un control con un id en particular. Por ejemplo podría tener una variable que sea el id del control. Entonces tomaríamos el valor de cualquier control que queramos. Podría tener otra variable que contenga el mensaje para la función alert(). Entonces podríamos variar el mensaje de respuesta al usuario.

<input type='text' id='usuario_entrada' onChange='guardarDato("usuario_entrada","Tu nombre es ")'>
<input type='text' id='usuario_edad' onChange='guardarDato("usuario_edad","Tu edad es ")'>
<script language='Javascript'>
	function guardarDato(id,msg){
		nombre_elemento= document.getElementById(id); 
		nombre= nombre_elemento.value; 
		alert("msg "+nombre)
	}
</script>

Probemos

Ingrese su nombre: Ingrese su edad:

Errores comunes

La función getElementById() es ejecutada por el objeto document, por eso no podemos llamarla por sí sola. Si ejecutamos getElementById es probable que no se ejecute nada o que el compilador busque la función y no la encuentre. Recuerda usarla de la forma document.getElementById().

Las funciones se deben llamar con los paréntesis aunque no tengan argumentos. Si se olvidan los paréntesis no se ejecuta la función, en su lugar se escribe el código de la función, o sea su valor. Por ejemplo: cuál es el código de la función document.getElementById()?

En los eventos podemos usar la variable especial this que se refiere al control que afecta el evento. Tiene la propiedad value que es el valor que guarda el control. Un ejemplo parecido al ejercicio anterior:

Ingrese su estado de ánimo: <input type='text' id='usuario_animo' onChange='dar_aviso(this.value,"Tu estado es ")'>
<script language='Javascript'>
	function dar_aviso(valor,msg){
		alert(msg + valor)
	}
</script>
Ingrese su estado de ánimo:

El caso de los senderos que se bifurcan

Pedimos un camino a seguir a través de una pregunta (confirm)

En la ejecución de un script las sentencias se van dando una tras otra, hasta llegar a un if (condicion)... else... que produce un salto a una porción de código o a otra según se cumpla la condición o no. Otras veces será el usuario el que decida y en Javascript le haremos la pregunta con la función confirm. La respuesta se corresponde entonces con true o false, en este caso dando Aceptar o Cancelar.

Supongamos que le damos al usuario la opción de saber en qué página está su navegador.

<input type='button' value='Pregunta' onClick='comunicar();'>
<script language='Javascript'>
function comunicar(){
	if (confirm ('Desea saber el link actual?')) { alert('El link actual es: '+ location.href) }
	else { alert ('No desea saberlo'); }
}
</script>
Usamos la función confirm para que el usuario decida una de entre dos cosas. La eleccián será verdadera si elige Aceptar, falso en caso contrario. Usamos location.href para mostrar la URL de la página actual. La propiedad href se aplica al objeto especial location.

Probemos

Supongamos que le damos al usuario la opción de saber en qué página está su navegador y la opción de saltar a otra página.

<input type='button' value='Bifurcación' onClick='saltar();'>
<script language='Javascript'>
function saltar(){
	if (confirm ('Desea saber el link actual?')) { alert('El link actual es: '+ location.href) }
	else { alert ('No desea saberlo'); }
	if (confirm ('Desea saltar a mi página favorita?')) { alert('www.misosguar.com.ar'); location.href= 'www.misosguar.com.ar'; }
	else { alert ('No desea saltar'); }
}
</script>

Probemos

Un problema sutílmente diferente es darle al usuario la opción de saber en qué página está y sólo en ese caso darle la opción de saltar a otra página.

<input type='button' value='Bifurcación' onClick='saltar_de_nuevo();'>
<script language='Javascript'>
function saltar_de_nuevo(){
	if (confirm ('Desea saber el link actual?')) { 
		alert('El link actual es: '+ location.href);
		if (confirm ('Desea saltar a mi p\u00E1gina favorita?')) { 
			alert('www.misosguar.com.ar'); 
			location.href= 'http://www.misosguar.com.ar'; }
		else { alert ('No desea saltar'); }
		}
	else { alert ('No desea saberlo'); }
}
</script>

Probemos de nuevo

No me funciona Javascript

Setear la propiedad href del objeto location produce que el navegador vaya a esa página seteada. Es común olvidar colocar el protocolo de la referencia URL. No es lo mismo http:// + la dirección de la página que olvidar poner el protocolo http://. En caso de olvidar colocar el protocolo, el navegador busca la página en el sitio actual.

Si por alguna razón no funciona asignar una dirección a location.href en tu script a pesar de estar bien escrita prueba agregar esta línea de código: return false;

El caso de los intervalos de tiempo

Esperamos un período de tiempo antes de hacer algo (setTimeOut)

A veces es necesario esperar cierto tiempo desde un evento a otro. Por ejemplo, si el usuario pasa el mouse por encima de un menú, podemos cambiar la imagen del menú para resaltar el evento, y esperar unos segundos para volverlo a la imagen normal. Otro ejemplo es tener contadores de segundos o mostrar un cronómetro o incluso mostrar la hora actualizando cada segundo. Para realizar estas tareas en Javascript disponemos de los temporizadores. Supongamos para nuestro ejemplo que tenemos un semáforo y que cada color dura 2 segundos. Podemos simular el semáforo con 3 imágenes, cada una con un color encendido y los otros apagados.

Previamente cargamos las imágenes en un arreglo (array):

var semaforo=new Array();
semaforo['rojo']=new Image();
semaforo['rojo'].src="red.gif"
semaforo['amarillo']=new Image();
semaforo['amarillo'].src="yellow.gif"
semaforo['verde']=new Image();
semaforo['verde'].src="green.gif"
var imagen_actual= 'rojo';

Luego mostramos la imagen actual:

<img src="rojo.gif" id="semaforo_img">

Probemos

Paremos un momento para probar el resultado final:

Para detener el semáforo, click aquí:

Usamos setInterval() para fijar la secuencia en milisegundos, en este caso 2 segundos son 2000 milisegundos. La función setInterval llamará a otra función, semaforo_control(), y devuelve un manejador de temporizador que guardamos en la variable tempo. La función clearInterval recibe la variable tempo para detener el temporizador. Usamos getElementById en semaforo_control para identificar la imagen en la página y asignar la imagen en su atributo src. He aquí el código:
<input value='Start' type='button' onClick='tempo= setInterval("semaforo_control()",2000)'>
<input value='Stop' type='button' onClick='clearInterval(tempo)'>
<script language='Javascript'>
function siguiente(actual, limite){
	actual++;
	if (actual>=limite) { actual = 0; }
	return actual;
}
function semaforo_control(){
	s= document.getElementById('semaforo_img');
	imagen_actual= siguiente(imagen_actual,secuencia.length);
	color= secuencia[imagen_actual];
	s.src= semaforo[color].src;
}
</script>
La función setInterval repite cada cierto tiempo. Pero si queremos solamente esperar un tiempo para hacer algo y no volver a repetir, usamos la función setTimeout(). Para cancelar la ejecución de setTimeout existe clearTimeout. En nuestro ejemplo quedaría:
<input value='Start' type='button' onClick='tempo= setTimeout("semaforo_control()",2000)'>
<input value='Stop' type='button' onClick='clearTimeout(tempo)'>
Y nuestro semáforo sólo cambiará de color una vez.

Alguien sabe cuánto tiempo está verde un semáforo? Para simular una situación de incertidumbre (vivo en Argentina, somos especialistas) podemos usar la función random() que devuelve un número aleatorio entre 0 y 1. Para obtener valores entre 2000 y 5000 debemos multiplicar el número por (5000-2000) y sumar 2000. valor_aleatorio= Math.random()*3000+2000;

Luego, si quieres redondear el valor retornado por random() utiliza round(). Por ejemplo round(1.5) es

Problemas con mi script

Si tu función recurrente, la que llamas con setInterval, no se ejecuta, fija que te faltaron las comillas. La función setInterval recibe como parámetro un string con la función que tiene que llamar. Es un error mandar la función directamente, aunque es poco intuitivo debe ir entrecomillada.

La función random() pertenece a la clase estática Math. No olvides usar Math.random(), no funcionará si usas sólo random(). Lo mismo para round().

El caso que estaba en preparación

Todavía sigue en preparación. Vuelve pronto para verlo terminado!

El caso de los selects múltiples que se relacionan

Si tenemos varios selects que están relacionados de alguna manera, podemos desear que al elegir un valor de uno de ellos los valores del otro cambien de alguna manera. Veamos un ejemplo:

Elije una fruta: Elije el color de la fruta:

Seguramente si el usuario elije Manzana de la lista, no espera ver el color Naranja en la lista de colores. Cuando nos encontramos con selects que se relacionan es necesario ser más eficientes. El usuario perderá menos tiempo eligiendo de la segunda lista si la reducimos después de la primera elección. Es más amigable con el usuario y más inteligente.

Selects inteligentes

Ahora elije a tu animal favorito! Primero elijes el tipo de alimentación de un select y se completa el otro select con los animales correctos:

Elije tu animal favorito:

Volviendo con las frutas y colores: Selecciona una fruta y un color para esa fruta!

Elije una fruta: Elije el color de la fruta:

Programando los selects

Los elementos SELECT se componen de elementos OPTION que tienen el atributo 'value' y 'text'. Vamos a formar un array con estos valores para cada SELECT, formando dos conjuntos de valores:

<script language='Javascript'>
// conjunto F de Frutas y C de Colores
F= {'0':'Naranja','1':'Manzana','2':'Banana'};
C= {'11':'Naranja','12':'Verde','13':'Roja','14':'Amarilla'};
</script>

A la relación entre los conjuntos de Frutas y Colores la llamaremos FxC y será otro array. Este array tendrá los atributos 'value' del conjunto F relacionados con los atributos value del conjunto C.

<script language='Javascript'>
// relacion entre el select Frutas y el select Colores
FxC= {'0':[11,12],'1':[12,13],'2':[14,12]};
</script>

La función 'jstruct.F()' se asocia al evento OnChange del select Frutas y es la función que realiza el trabajo difícil por nosotros. Necesita conocer el elemento seleccionado, id del select Colores, el conjunto con el que se relaciona el select y la relación en sí.

<select onChange='jstruct.F(this.value,F,FxC,"color")'>
<option value='0'>Naranja</option>
<option value='1'>Manzana</option>
<option value='2'>Banana</option>
</select>

La librería jStruct es libre y puede verse y descargarse del siguiente link:

Ver el código completo y descargar los archivos

El caso del formato de fecha sin control

Introducir datos en formularios es complicado. El usuario siempre aprende a romper nuestro código. También puede ser que el usuario se queje de que el formulario es el complicado o que no tiene suficiente ayuda. Por ejemplo ingresar una fecha en un cuadro de texto no requiere ningún esfuerzo extra si el dato no va a ser procesado, no va a calcular diferencias de fechas o cuál fecha es menor o mayor, o sea, es un simple texto. Pero si son requeridos procesamientos de este estilo, el formato de fecha es fundamental para saber qué número es el año o el día o el mes. Introducir la fecha sin ningún tipo de seguimiento da lugar a interpretaciones ambiguas. Por ejemplo, cómo separo la fecha, con barra o con guión, primero el año o lo dejo para el final. Qué fecha es 12/08/08? Será el 12 de agosto del 2008? O el 8 de agosto del 2012? Necesitamos advertir al usuario para que sepa de antemano el formato de fecha que se requiere. Sin molestarlo, más bien dándole sugerencias si algo va mal encaminado. Lo que vamos a hacer es un seguimiento de la entrada del usuario en el cuadro de texto (input text) informando cuál es el formato deseado.

Nota: Hay muy buenos controles para el ingreso de fechas que simulan almanaques y son muy aconsejables. Pero requieren un diestro manejo del mouse, algunos usuarios consideran más rápido entrar la fecha por teclado.

Guiamos al usuario mientras entra la información

El usuario coloca el foco en el cuadro de texto donde ingresa la fecha. En ese momento se ejecuta el evento onFocus y lo usamos para mostrar nuestro control especial que guiará al usuario:

tooltip

El usuario empieza a editar el texto, en cada pulsación del teclado se ejecuta el evento onKeyUp que usamos para saber cuál es el último cambio que hizo el usuario a la fecha y chequearla con el formato:

tooltip le sigue tooltip

Para colocar el control guía sobre el control input usamos la clase Insertion.Before que sabe insertar HTML antes de un elemento. Luego la posición la buscamos con offsetTop y offsetLeft. Con offsetTop encontramos la distancia en píxeles desde control input hasta el tope del navegador, y con offsetLeft la distancia desde el control hasta el borde izquierdo del navegador. El control guía es posicionado en forma absoluta y le asignamos su posición en píxeles en sus propiedades style.top y style.left.

Probemos

Introducir Fecha:

El código operativo es:

<script language='Javascript'>
var mitip= new ControlFielShip('mitooltip');	// mi objeto amistoso
</script>
Introducir Fecha: 
<input type='text' name='fecha' id='fecha' onKeyUp='mitip.check(this.value)' onFocus='mitip.show()' onBlur='mitip.hide()'>
<script language='Javascript'>
// se podría usar: 
mitip.formato('dd-mm-aaaa');
// pero uso un sinónimo
mitip.formato_ARG();	// asigno el formato dd-mm-aaaa
mitip.input('fecha');	//asigno el control input de fecha (y creo el div tooltip)
// un consejo útil
mitip.consejo('Formato: dd/mm/aaaa Ejemplo: 28/12/2008');
</script>
<BR>
<input type='button' value="Ver Fecha" onClick='alert($("fecha").value)'>

La clase ControlFieldShip esconde la funcionalidad del control y es donde se ejecuta Insertion.Before, offsetTop y offsetLeft. La definición de la clase es Javascript y puede incluirse en el mismo archivo o en uno aparte. La función Insertion.Before por ejemplo pertenece a una librería llamada Prototype y se incluye en otro archivo. También usamos una hoja de estilos para el control que le aplica color y posicionamiento.

El código para incluir los archivos es:

<link rel="stylesheet" href="controlfecha/estilosilph.css" type="text/css"> 
<script type="text/javascript" src="prototype.js">
<script type="text/javascript" src="controlfecha/controlsilph.js">

En Prototype se define la función $() que toma un string y devuelve el elemento DOM identificado por ese string. Además implementa la manera de programar en objetos y crear clases, vea al respecto el tutorial de Sergio Pereira.

Se puede extender la clase ControlFielShip para agregar más funcionalidades al control.

Ver el código completo y descargar los archivos

Encontrando el error

Cuando se codifican clases y se decide ponerle nombre a los métodos y atributos del objeto, algunos lenguajes permiten que se use el mismo nombre. No es este el caso. Por ejemplo si decido que el método que modifica el formato de fecha se llame formato() y que mi objeto tenga un atributo llamado formato, voy a tener un conflicto de nombres. La solución que encontré para seguir con mi costumbre, fue iniciar en mayúsculas los nombres de propiedades para diferenciarlos de los métodos que nombre en minúsculas. Javascript diferencia entre mayúsculas y minúsculas entonces le parecen nombres diferentes y no genera conflicto.

Usar variables globales no es aconsejable. Pero si se usan hay que tener en cuenta el alcance de la variable. Por ejemplo una función F no puede invocar a una variable que es local de otra función G. En el caso de que sea necesario hacerlo así, como en el caso de la clase ControlFieldShip y su función check(), la función F debe ser local a la función G para poder ver su variable en forma global. Mira el código.