Saca tus scripts de tu código HTML

Buenas! En el post anterior os comenté el soporte de Unobtrusive Ajax en ASP.NET MVC3. Hoy quiero mostraros que esa técnica ni es exclusiva de MVC3, ni  requiere HTML5 para nada. En fin, que podéis empezar a usarla ya, con independencia de la tecnología que uséis. Lo que contaré en este artículo no es nada “revolucionario” ni una “técnica nueva”…

De hecho, el ejemplo va a ser una página HTML, nada de ASP.NET 🙂

Veamos, la técnica de Unobtrusive Javascript, se refiere a no tener mezclado código javascript con código de marcado HTML. Es decir, no queremos algo como:

<input type="text" id="txtName" onkeypress="checkKey();" />

Aquí estamos mezclando código HTML con el código javascript (la llamada checkKey en el onkeypress).

Imaginemos que queremos que nuestros textboxes sólo acepten números. Y recordad que el objetivo es no tener código javascript mezclado con nuestro código HTML.

Eso lo podemos conseguir fácilmente, ya con jQuery:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Demo Unobtrusive Javascript</title>
<script src="jquery-1.4.1.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
$(document).ready(function () {
$('input:text').keypress(function (event) {
if (event.keyCode < 47 || event.keyCode > 58) {
event.preventDefault();
}
});
});
</script>

Introduce sólo números: <br />
<input type="text" />
</body>
</html>

Incluso, si no queréis que haya el tag <script> con todo el código, podemos moverlo a un .js separado y usarlo desde nuestra página HTML que entonces quedaría como:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Demo Unobtrusive Javascript</title>
<script src="jquery-1.4.1.js" type="text/javascript"></script>
<script src="myscript.js" type="text/javascript"></script>
</head>
<body>
Introduce sólo números: <br />
<input type="text" />
</body>
</html>

Por lo tanto vemos que con jQuery es muy fácil asignar comportamiento a objetos DOM, sin necesidad de andar con los handlers onXXXX.

Ahora bien, el código jQuery selecciona todos los <input type=”text”>, que passa si sólo quiero seleccionar algunos? Como le indico a mi código jQuery que sólo algunos textboxes son numéricos?

Una solución es invertarnos un atributo que indique que elementos queremos como numéricos. De esta manera p.ej. la página HTML queda como:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Demo Unobtrusive Javascript</title>
<script src="jquery-1.4.1.js" type="text/javascript"></script>
<script src="myscript.js" type="text/javascript"></script>
</head>
<body>
Introduce sólo números: <br />
<input type="text" datatype="numeric" /> <br />
Aquí puedes introducir lo que quieras: <br />
<input type="text" />
</body>
</html>

Fijaos en el “datatype=”numeric” que es el atributo que me va a servir para decidir que textboxes son numéricos.

Y el código de myscript.js queda como:

$(document).ready(function () {
$('input[datatype=numeric]').keypress(function (event) {
if (event.keyCode < 47 || event.keyCode > 58) {
event.preventDefault();
}
});
});

Y listos, simplemente incluyendo “myscript.js” en cualquier página ya podemos declarar que un textbox es numérico simplemente poniendo el atributo datatype=”numeric”.

Ahora, si alguien hace otra librería javascript para textboxes numéricos si también usa este atributo para indicarlos (ahí está el quid de la cuestión) simplemente cambiando el <script> para que en lugar de ir a myscript.js vaya a la nueva librería, ya tengo todo el cambio hecho… es decir, me he independizado del framework javascript que use.

Y por ahí por donde entra HTML5? Pues bien, como eso de crearnos nuestros propios atributos está bien pero genera HTML que podríamos llamar inválido (en el sentido de que estos atributos no forman parte de HTML), para HTML5 han decidido simplemente que todos estos atributos “inventados” empiecen por data-.

Lo “único” que dice al respecto HTML5 es: “Hey, si tienes que invertarte un atributo para lo que sea, haz que su nombre empiece por data-. Todos los atributos que empiecen por data- son atributos inventados por alquien y deben ser ignorados a todos los efectos (salvo para quien lo haya inventado que hará con él lo que le plazca, claro). Ok, también añade una API específica (element.dataset) para leer esos atributos (pero eso de momento no nos importa ya que no está soportada por la mayoría de navegadores).

Por lo tanto, si en lugar de que mi atributo se llame datatype, hago que le llame data-datatype (p.ej. cualquier nombre que empiece por data-) ya lo tengo todo HTML5 compliant!

De hecho podéis hacer la prueba en http://validator.w3.org/check. Entráis el código HTML de la página y lo validáis contra:

  • HTML5 usando el atributo datatype=”numeric” y os dará error (Attribute not allowed)
  • HTML5 usando el atributo data-datatype=”numeric” y os validará correctamente.
  • Cualquier otra versión de HTML y os dará error en ambos casos.

Y listos! Por lo tanto fijaos que desde ya podeis empezar a aplicar técnicas de “Unobtrusive Javascript”: no necesitáis HTML5 para nada, ni MVC3 ni nada y la recompensa es un HTML mucho más claro y sencillo de ver!

Mi opinión es que, gracias a que HTML5 ha definido un espacio de nombres (data-) para los atrbutos inventados empezaremos a ver, cada ves más, librerías de javascript que usarán esos atributos, y seguramente algunos de ellos terminarán siendo estándares de facto (si yo hago una librería de javascript para validación. pues intentaré usar los mismos atributos data- que use la librería que sea líder en aquel momento, para compatibilizarme con ella).

Por cierto, si vais a usar muchos atributos data- en vuestras páginas web, echadle un vistazo a este plugin de jQuery: HTML5 Dataset.

Un saludo!

Nota: El código de ese artículo lo he probado con IE9 y Firefox 3.6.10.

9 comentarios en “Saca tus scripts de tu código HTML”

  1. Excelente el artículo.

    Está claro que esto mejor de forma notable la legibilidad del código HTML y evita en gran parte la duplicidad de código, que podía generarse antes…

  2. Hola,

    Otra técnica para no tener que inventarte un atributo es establecer una clase de CSS que identifique a esos elementos.

    Ejemplo:

    Recordemos que podemos aplicar varias clases CSS a una misma etiqueta. Si tambien queremos controlar con JQuery que sea un campo obligatorio podríamos crear la siguiente etiqueta.

    Con esto conseguimos que el XHTML generado sea válido.

    Gracias por el apunte de HTML5.

  3. @Juanjo
    Buenas! Exacto, crear clases es otra de las opciones para asignar comportamiento. Y sí, tiene la ventaja de que el XHTML es válido. 🙂
    El “inconveniente” es que estamos usando algo destinado a clasificar apariencia para añadir comportamiento. No es que no funcione, pero el comportamiento debería ir siempre ligado a atributos, por eso es de agradecer que en HTML5 nos hayan ofrecido por fin una solución a esto! 😀
    Muchas gracias por tu aporte!! 😉

    @Javier
    Muchas gracias! Encantado de que el artículo te haya gustado. 😀

  4. Como manejas el codigo js como el del ejemplo, es decir el de jquery dentro de un updatepanel. Pregunto esto porque me resulta muy incomodo escribir en el load de la pagina un scriptmanger para insertarlo ya q luego de un rountrip al servidor el codigo jquery deja de funcionar por el updatepanel.

    Como lo manejas inteligentemente a esto ???

  5. @Raul
    Buenas, si regeneras el DOM (que es lo que entiendo que hace el UpdatePanel) debes volver a ejecutar el código jQuery que te capture los eventos, ya que elementos originales no existen.

    No te puede decir como hacerlo exactamente, porque no he trabajado mucho del UpdatePanel, pero lo ideal sería que se ejecutase un méotdo javascript (p.ej. attachEvents()) cada vez que el UpdatePanel refrescase parte de la página.
    Este método es el que tendría todo el código jQuery (y de hecho en el document.load llamarías a ese mismo método).

    Un saludo!

  6. Hola, excelente aporte ahorra mucho tiempo y ordena enormemente el código, te pasaste. Tengo la siguiente duda, una vez que se ejecuta un evento de un elemento especifico y coincide con el nuevo atributo, como hago para identificar ese elemento especifico?.

    Me explico con un ejemplo, quiero aparte de usar keypress, tambien usar el elemento blur, ya que cuando se pierda el foco en algun elemento comprobar/validar un valor numerico de este y quizás modificar el valor en el campo especifico, pero si aplico esto al nuevo tag datatype me cambiara el valor en todos los elementos de ese tag.

    Gracias!.

  7. @Álvaro
    No hay problema… En la función “gestora” del evento (si usas jQuery) puedes usar $(this) para saber sobre que elemento se aplica el evento.
    P.ej. el siguiente código, en el blur valida si un campo es numerico y SÓLO si lo es, le añade un “0” al principio. Esta validación se aplicará a todos los campos que tengan el atributo data-foo:

    Cuando un elemento pierda el foco, se mira su valor y si su valor es numérico se le añade un 0 al principio. Para probarlo puedes añadir varios textboxes en una página:



    Y verás como sólo los “data-foo” tienen este comportamiento (pero sólo afecta al que pierda el foco).

    El valor de data-foo es irrelevante, lo único que se mira es que el atributo esté (aunque eso se puede cambiar).

    Saludos!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *