lunes, 4 de septiembre de 2017

Javascript Parte LXI

Como hemos visto hasta ahora uno de los usos principales de JavaScript es la implementación de algoritmos que reaccionan a eventos que se producen en una página web. Cuando se termina de cargar completamente una página web se dispara el evento onload, cuando se presiona un botón de tipo submit se dispara el evento onsubmit, cuando movemos la flecha del mouse se dispara onmousemove y otra gran cantidad de eventos que nos informa el navegador y nosotros podemos capturarlos y hacer un algoritmo a nuestra medida.
JavaScript implementa tres formas distintas de capturar los eventos que emite el navegador.

Eventos definidos directamente en la marca HTML.

Esta metodología esta en desuso, de todos modos muchos sitios creados a fines de 1990 y principios del 2000 implementan esta técnica.
Problema
Implementar un formulario que solicite la carga del nombre de usuario y su clave. Mostrar un mensaje si no se ingresan datos en alguno de los dos controles.
<html>
<head>

<script type="text/javascript">

  function validar()
  {
     var usu=document.getElementById("usuario").value;
     var cla=document.getElementById("clave").value;
     if (usu.length==0 || cla.length==0)
     {
       alert('El nombre de usuario o clave está vacío');
       return false;
     }
     else
       return true;
  }

</script>

</head>
<body>

<form method="post" action="procesar.php" onsubmit="validar();" id="formulario1">
Ingrese nombre:
<input type="text" id="usuario" name="usuario" size="20">
<br>
Ingrese clave:
<input type="password" id="clave" name="clave" size="20">
<br>
<input type="submit" id="confirmar" name="confirmar" value="Confirmar">
</form>

</body>
</html>
Lo primero que tenemos que ver que la marca form define la propiedad onsubmit y le asigna el nombre de la función JavaScript que debe llamarse previo a que el navegador empaquete todos los datos del formulario y los envía al servidor para ser procesados:
<form method="post" action="procesar.php" onsubmit="validar();">
Como vemos debemos indicar el nombre de la función y los paréntesis (en este caso no se envían parámetros por lo que los paréntesis van abiertos y cerrados)
En el bloque JavaScript debemos implementar la función validar donde extraemos los valores de cada control y verificamos si alguno de los dos no tiene cargado caracteres, en caso que suceda esto mostramos un mensaje y retornamos un false para que el navegador no envíe los datos del formulario al servidor. Si la función retorna true los datos del formulario son enviados por el navegador al servidor:
<script type="text/javascript">

  function validar()
  {
     var usu=document.getElementById("usuario").value;
     var cla=document.getElementById("clave").value;
     if (usu.length==0 || cla.length==0)
     {
       alert('El nombre de usuario o clave está vacío');
       return false;
     }
     else
       return true;
  }

</script>
Esta metodología de inicializar eventos debe ser evitada en todo lo posible.

Eventos definidos accediendo a propiedades del objeto.

Esta metodología es todavía ampliamente utilizada ya que la mayoría de los navegadores lo implementan en forma similar.
Problema
Implementar un formulario que solicite la carga del nombre de usuario y su clave. Mostrar un mensaje si no se ingresan datos en alguno de los dos controles.
<html>
<head>

<script type="text/javascript">

  window.onload=inicio;

  function inicio()
  {
    document.getElementById("formulario1").onsubmit=validar;
  }

  function validar()
  {
     var usu=document.getElementById("usuario").value;
     var cla=document.getElementById("clave").value;
     if (usu.length==0 || cla.length==0)
     {
       alert('El nombre de usuario o clave está vacío');
       return false;
     }
     else
       return true;
  }

</script>

</head>
<body>

<form method="post" action="procesar.php" id="formulario1">
Ingrese nombre:
<input type="text" id="usuario" name="usuario" size="20">
<br>
Ingrese clave:
<input type="password" id="clave" name="clave" size="20">
<br>
<input type="submit" id="confirmar" name="confirmar" value="Confirmar">
</form>

</body>
</html>
Con esta segunda metodología vemos que el código HTML queda limpio de llamadas a funciones JavaScript y todo el código queda dentro del bloque del script (pudiendo luego llevar todo este bloque a un archivo externo *.js)
Lo primero que vemos es inicializar la propiedad onload del objeto window con el nombre de la función que se ejecutará cuando finalice la carga completa de la página, es importante notar que a la propiedad onload le asignamos el nombre de la función y NO debemos disponer los paréntesis abiertos y cerrados (ya que no se está llamando a la función sino le estamos pasando la dirección o referencia de la misma)
  window.onload=inicio;
La función inicio es llamada por el objeto window cuando se termina de cargar la página. En esta función obtenemos la referencia del objeto formulario1 mediante el método getElementById e inicializamos la propiedad onsubmit con el nombre de la función que será llamada cuando se presione el botón submit del formulario:
  function inicio()
  {
    document.getElementById("formulario1").onsubmit=validar;
  }
Por último tenemos la función validar que verifica si los dos controles del formulario están cargados:
  function validar()
  {
     var usu=document.getElementById("usuario").value;
     var cla=document.getElementById("clave").value;
     if (usu.length==0 || cla.length==0)
     {
       alert('El nombre de usuario o clave está vacío');
       return false;
     }
     else
       return true;
  }
La misma metodología pero utilizando funciones anónimas para cada evento el código ahora queda condensado:
<html>
<head>

<script type="text/javascript">

  window.onload=function() {
    document.getElementById("formulario1").onsubmit=function () {
      var usu=document.getElementById("usuario").value;
      var cla=document.getElementById("clave").value;
      if (usu.length==0 || cla.length==0)
      {
        alert('El nombre de usuario o clave está vacío');
        return false;
      }
      else
        return true;
    }
  }

</script>

</head>
<body>

<form method="post" action="procesar.php" id="formulario1">
Ingrese nombre:
<input type="text" id="usuario" name="usuario" size="20">
<br>
Ingrese clave:
<input type="password" id="clave" name="clave" size="20">
<br>
<input type="submit" id="confirmar" name="confirmar" value="Confirmar">
</form>

</body>
</html>
Analicemos un poco el código implementado, a la propiedad onload del objeto window le asignamos una función anónima:
  window.onload=function() {
     ...
  }
En la implementación de la función anónima inicializamos la propiedad onsubmit del objeto formulario1 con otra función anónima:
    document.getElementById("formulario1").onsubmit=function () {
      ...
    }
Esta sintaxis de funciones anónimas es ampliamente utilizado.

Modelo de eventos definidos por W3C (World Wide Web Consortium)

Este modelo de eventos se basa en la implementación de un método para todos los objetos que nos permite registrar eventos. La sintaxis del método es:
  addEventListener(evento, método a ejecutar, fase);
Veamos como implementamos el problema anterior utilizando este nuevo modelo de eventos:
<html>
<head>

<script type="text/javascript">

  window.addEventListener('load',inicio,false);

  function inicio()
  {
    document.getElementById("formulario1").addEventListener('submit',validar,false);
  }

  function validar(evt)
  {
     var usu=document.getElementById("usuario").value;
     var cla=document.getElementById("clave").value;
     if (usu.length==0 || cla.length==0)
     {
       alert('El nombre de usuario o clave está vacío');
       evt.preventDefault();
     }
  }

</script>

</head>
<body>

<form method="post" action="procesar.php" id="formulario1">
Ingrese nombre:
<input type="text" id="usuario" name="usuario" size="20">
<br>
Ingrese clave:
<input type="password" id="clave" name="clave" size="20">
<br>
<input type="submit" id="confirmar" name="confirmar" value="Confirmar">
</form>

</body>
</html>
Lo primero que vemos es que en vez de inicializar la propiedad onload procedemos a llamar al método addEventListener:
  window.addEventListener('load',inicio,false);
El primer parámetro es un string con el nombre del evento a inicializar, el segundo parámetro es el nombre de la función a ejecutar y el tercer parámetro normalmente es el valor false.
Cuando se carga completamente la página el objeto window tiene la referencia al método que se debe llamar, en nuestro caso se llama inicio. La función inicio obtiene la referencia del objeto formulario1 y procede a registrar el evento submit indicando en el segundo parámetro el nombre de la función que debe ejecutarse:
  function inicio()
  {
    document.getElementById("formulario1").addEventListener('submit',validar,false);
  }
El código de la función validar se modifica, llega como parámetro una referencia al evento y mediante este llamamos al método preventDefault si queremos que no se envíen los datos al servidor:
  function validar(evt)
  {
     var usu=document.getElementById("usuario").value;
     var cla=document.getElementById("clave").value;
     if (usu.length==0 || cla.length==0)
     {
       alert('El nombre de usuario o clave está vacío');
       evt.preventDefault();
     }
  }
Este modelo de eventos está siendo ampliamente implementado por los navegadores modernos. El problema es el IE8 o inferiores que no lo implementa de esta forma.

Javascript Parte LX

Hasta ahora siempre que hemos implementado una función le hemos pasado como parámetro tipos de dato numérico, string, boolean, objetos etc.
Ahora veremos que también podemos implementar funciones que reciban como parámetro otra función.
Primero veamos un simple ejemplo para entender que una función se la podemos asignar a una variable y luego a través de esta variable llamar a la función:
<html>
<head>
</head>
<body>

<script type="text/javascript">

  var f1=function(x,y)
  {
    var s=x+y;
    return s;
  }

  document.write(f1(4,6)+'<br>');  
  var f2=f1;
  document.write(f2(3,3)+'<br>');    

</script>

</body>
</html>
Vemos que definimos una variable llamada f1 y le asignamos la función propiamente dicha:
  var f1=function(x,y)
  {
    var s=x+y;
    return s;
  }
Luego para llamar la función lo hacemos a través de la variable f1:
  document.write(f1(4,6)+'<br>');  
De la misma manera podemos definir una segunda variable que obtenga la referencia de la otra variable y podremos entonces llamar a la misma función con este segundo nombre:
  var f2=f1;
  document.write(f2(3,3)+'<br>');    
Problema
Ahora si implementaremos otro problema que declare una función que reciba tres parámetros, el último de ellos es una función:
<html>
<head>
</head>
<body>

<script type="text/javascript">

  function calcular(x,y,fu)
  {
    var resu=fu(x,y);
    return resu;
  }

  var s1=calcular(10,5,function (v1,v2) {
    return v1+v2;
  });
  
  document.write(s1+'<br>');

  var s2=calcular(10,5,function (v1,v2) {
    return v1-v2;
  });
  
  document.write(s2+'<br>');


</script>

</body>
</html>
Es importante entender la sintaxis que presentamos en este problema elemental para entender que una función puede recibir como parámetros una función y luego llamarla desde dentro.
Primero analicemos como llamamos a la función calcular:
  var s1=calcular(10,5,function (v1,v2) {
    return v1+v2;
  });
A la función calcular le pasamos dos enteros:10 y 5, y una función que definimos en el mismo parámetro:
function (v1,v2) {
    return v1+v2;
}
La función calcular recibe los tres parámetros y sabiendo que el tercer parámetro llega la referencia a la función procedemos a llamarla enviando los dos parámetros requeridos:
  function calcular(x,y,fu)
  {
    var resu=fu(x,y);
    return resu;
  }
Como vemos podemos llamar nuevamente a la función calcular pero pasando otra función:
  var s2=calcular(10,5,function (v1,v2) {
    return v1-v2;
  });
Podemos en vez de definir funciones anónimas cuando llamamos a calcular pasar el nombre de funciones declaradas:
<html>
<head>
</head>
<body>

<script type="text/javascript">

  function sumar(v1,v2) 
  {
    return v1+v2;
  }

  function restar(v1,v2) 
  {
    return v1-v2;
  }

  function calcular(x,y,fu)
  {
    var resu=fu(x,y);
    return resu;
  }

  var s1=calcular(10,5,sumar);
  
  document.write(s1+'<br>');

  var s2=calcular(10,5,restar);
  
  document.write(s2+'<br>');

</script>

</body>
</html>
Podemos observar que definimos las funciones sumar y restar:
  function sumar(v1,v2) 
  {
    return v1+v2;
  }

  function restar(v1,v2) 
  {
    return v1-v2;
  }
Y cuando llamamos a calcular en el tercer parámetro indicamos el nombre de la función a enviarle:
  var s1=calcular(10,5,sumar);

Javascript Parte LIX

JavaScript permite definir funciones dentro de otras funciones:
<html>
<head>
<script type="text/javascript">


  function generarListaOrdenada(vec)
  {
    function comienzo()
    {
      s='<ol>';
    }
  
    function fin()
    {
      s=s+'</ol>';
    }
    
    var s='';
    comienzo();
    var f;
    for(f=0;f<vec.length;f++)
    {
      s=s+'<li>'+vec[f]+'</li>';
    }
    fin();
    return s;
  }


  onload=function() {
    var opciones=['Opción a','Opción b','Opción c','Opción d'];
    document.getElementById('div1').innerHTML=generarListaOrdenada(opciones);
  }

</script>

</head>
<body>
<div id="div1"></div>
</body>
</html>
Como vemos en el ejemplo la función generarListaOrdenada contiene el algoritmo propiamente dicho y además declara dos funciones llamadas comienzo y fin.
Las funciones anidadas solo pueden ser llamadas desde el interior de la función que las contiene. En este ejemplo la función generarListaOrdenada tiene por objetivo generar un string con una serie de marcas HTML que genere una lista ordenada.
Lo primero en la función generarListaOrdenada es declarar las dos funciones anidadas:
    function comienzo()
    {
      s='<ol>';
    }
  
    function fin()
    {
      s=s+'</ol>';
    }
Pero lo primero que se ejecuta al llamar a la función generarListaOrdenada es:
    var s='';
    comienzo();
    var f;
    for(f=0;f<vec.length;f++)
    {
      s=s+'<li>'+vec[f]+'</li>';
    }
    fin();
    return s;
Es decir primero se define la variable local s y se inicializa con un string vacío. Seguidamente se llama a la función comienzo que tiene por objetivo cargar en la variable s el valor '<ol>'.
Cuando finaliza de ejecutarse la función interna continua con el for definido en la función generarListaOrdenada:
    for(f=0;f<vec.length;f++)
    {
      s=s+'<li>'+vec[f]+'</li>';
    }
Finalmente cuando sale del for se llama a la segunda función anidada llamada fin:
    fin();
Las funciones anidadas pueden acceder a las variables locales de la función que las contiene (en este caso pueden acceder a la variable s)
Luego la función generarListaOrdenada completa queda con la sintaxis:
  function generarListaOrdenada(vec)
  {
    function comienzo()
    {
      s='<ol>';
    }
  
    function fin()
    {
      s=s+'</ol>';
    }
    
    var s='';
    comienzo();
    var f;
    for(f=0;f<vec.length;f++)
    {
      s=s+'<li>'+vec[f]+'</li>';
    }
    fin();
    return s;
  }
A la función generarListaOrdenada la llamamos desde la función anónima que definimos para el evento onload de la página. Cargamos en el elemento div definido dentro de la página el código HTML que genera una lista ordenada:
  onload=function() {
    var opciones=['Opción a','Opción b','Opción c','Opción d'];
    document.getElementById('div1').innerHTML=generarListaOrdenada(opciones);
  }
Las funciones anidadas no se las puede llamar desde fuera de la función que las contiene, por ejemplo produce un error si intentamos llamar a la función "comienzo" desde fuera de la función generarListaOrdenada:
  onload=function() {
    var opciones=['Opción a','Opción b','Opción c','Opción d'];
    comienzo();
    document.getElementById('div1').innerHTML=generarListaOrdenada(opciones);
  }

Javascript Parte LVIII

Cuando definimos una función podemos emplear letras minúsculas, mayúsculas, números siempre y cuando no ocupe la primer posición en el nombre, el caracter '_' y el caracer '$'
Una convención muy extendida cuando se define una función es comenzar la primera palabra en minúscula y a partir de la segunda palabra disponer el primer caracter en mayúsculas:
<html>
<head>
</head>
<body>

<script type="text/javascript">
 
  function calcularPerimetro(lado)
  {
    var per=lado*4;
    return per;
  }

  var l=prompt('Ingrese valor del lado:','');
  l=parseInt(l);
  document.write(calcularPerimetro(l));

</script>

</body>
</html>
El nombre de la función en este ejemplo es: calcularPerimetro
Como vemos la primer palabra "calcular" hemos utilizado todo minúsculas y en la segunda palabra disponemos en mayúsculas el primer caracter "Perimetro".
Las funciones estándares de JavaScript tienen esta convención:
parseInt
parseFloat
prompt
Los métodos de distintas clases (Date, String) también cumplen esta convención:
 getYear()
 setYear(año)
 getFullYear()

 toUpperCase()
 toLowerCase()
 indexOf()

 etc.
Siempre es conveniente utilizar nombres de funciones que sean significativas con el algoritmo que implementan: calcularPerimetro, sumar, calcularRaizCuadrada etc.
La regla de definir un nombre de función lo más claro posible puede saltearse con funciones que se utilizan constantemente (por ejemplo la librería JQuery de JavaScript define una función que tiene como nombre solo el caracter $)
Emplear un solo caracter para definir un nombre de función solo se aconseja para funciones de uso masivo.
Problema
Definir una función llamada $ que reciba como parámetro el id de un elemento HTML y retorne la referencia del mismo.
<html>
<head>

<script type="text/javascript">

  function $(ele)
  {
    return document.getElementById(ele);
  }

  function inicio()
  {
    $('cuerpo').style.backgroundColor='#ffff00';
  }

  window.onload=inicio;

</script>

</head>
<body id="cuerpo">

</body>
</html>
La función $ recibe como parámetro el id de un elemento HTML y mediante el método getElementById extrae la referencia y lo retorna:
  function $(ele)
  {
    return document.getElementById(ele);
  }
La función inicio se ejecuta luego que la página está completamente cargada. Llama a la función $ pasando el id del body de la página y con el valor devuelto accedemos a la propiedad style del objeto:
  function inicio()
  {
    $('cuerpo').style.backgroundColor='#ffff00';
  }

Javascript Parte LVII

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.
<html>
<head>
</head>
<body>

<script type="text/javascript">

  function imprimir()
  {
    var x=10;
    document.write(x);
  }

  imprimir();

</script>

</body>
</html>
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:
<script type="text/javascript">

  function imprimir()
  {
    var x=10;
    document.write(x);
  }

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

  </script>
Las variables globales son las que definimos fuera de cualquier función. Una variable global tenemos acceso fuera y dentro de las funciones:
<html>
<head>
</head>
<body>

<script type="text/javascript">

  function imprimir()
  {
    document.write(global1+'<br>');  // muestra un 100
    global1++;
  }

  var global1=100;
  imprimir();
  document.write(global1);  // muestra un 101

</script>

</body>
</html>
Como podemos observar el programa anterior hemos definido la variable global1 e inicializado con el valor 100. Luego dentro de la función podemos acceder para imprimirla y modificarla. Podemos ver luego si la accedemos fuera de la función su valor fue modificado.
Todas las variable globales se convierten en atributos del objeto window, luego podemos acceder a la variable por su nombre o antecediendo el nombre del objeto:
<html>
<head>
</head>
<body>

<script type="text/javascript">

  var global1=100;
  document.write(global1+'<br>');        //100
  document.write(window.global1+'<br>'); //100

</script>

</body>
</html>
Cuidado
Cuando definimos variables locales dentro de una función tenemos que no olvidarnos de anteceder al nombre de la variable la palabra var, en caso de olvidarnos se creará automáticamente una variable global con dicho nombre:
<html>
<head>
</head>
<body>

<script type="text/javascript">
  
  function imprimir()
  {
    x=100;
    document.write(x+'<br>');
  }

  imprimir();
  document.write(x+'<br>');
  
</script>

</body>
</html>
En el ejemplo superior en la función imprimir se está creando una variable global llamada x. Como podemos ver luego fuera de la función cuando imprimimos x vemos que no produce error y muestra el valor 100. Con solo agregar la palabra clave var vemos que nos muestra un mensaje de error al tratar de acceder a una variable inexistente:
  function imprimir()
  {
    var x=100;
    document.write(x+'<br>');
  }

  imprimir();
  document.write(x+'<br>');
El JavaScript moderno introduce una directiva para salvar este y otros problemas muy comunes. Si activamos modo estricto todas las variables en JavaScript deben declarase sino se produce un error. Veamos como introducimos esta directiva de modo estricto:
<html>
<head>
</head>
<body>

<script type="text/javascript">
  
  'use strict';

  function imprimir()
  {
    x=100; //error
    document.write(x+'<br>');
  }

  imprimir();
  document.write(x+'<br>');
  
</script>

</body>
</html>
La directiva de modo estricto se emplea las palabras claves use strict entre comillas simples o dobles y un punto y coma. Solo los navegadores modernos implementan los análisis de modo estricto.
La razón de disponer la directiva entre comillas y con un punto y coma es para que navegadores antiguos pasen por alto el string (ya que el string no se asigna a nadie el navegador antiguo no lo tiene en cuenta)
Activando el modo estricto luego cuando tratamos de asignar el valor 100 a la variable x se produce un error ya que no se nos permite crear una variable global (esto nos evita problemas de crear variables globales en funciones por error)