miércoles, 8 de agosto de 2012

Plug-in de jQuery para aceptar sólo números

Estoy comenzando un proyecto en ASP.NET Web Forms y he decidido no utilizar ninguna librería de terceros de controles de servidor de ASP.NET.

De este modo, ya no tengo disponibles maravillosos controles de servidor del tipo NumericTextBox que, con franqueza, me hacían la vida muy fácil y evitaban tener que controlar que la entrada del usuario eran sólo números.

Cómo lógicamente hay que seguir validando la entrada del usuario, he optado por crear mi propio plug-in de jQuery para restringir la entrada del usuario a sólo números en cajas de texto.

Cierto es que la idea original surgió a raíz de un post de @smarreof, jQuery input text numérico. Te recomiendo que lo leas para entrar en materia… bueno ese post y cualquier otro que tenga en su blog!. Además me ha ayudado con un comentario en el post sobre parseInt que ya he incluido en el código.

Lo primero es lograr una función de validación que sea lo más completa posible.

Como en la función vamos a hablar de la propiedad keyCode del objeto evento de javascript, aquí te dejo una referencia que a mi me ha sido de utilidad http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes

La idea es lograr una función que acepte sólo números (sin decimales) y además poder establecer un valor máximo para la caja de texto.

La función es la siguiente:

function numericTextBox(e) {
        if (
            e.keyCode == 8 // backspace
            || e.keyCode == 9 // tab
            || e.keyCode == 13 // enter
            || e.keyCode == 27 // escape
            || e.keyCode == 46 // delete
            || (e.keyCode >= 35 && e.keyCode <= 39) // end, home, left arrow, up arrow, right arrow
        ) {
            return;
        }
        else {
            if (!((e.keyCode >= 48 && e.keyCode <= 57) || (e.keyCode >= 96 && e.keyCode <= 105))) {
                // not 0-9, numpad 0-9
                e.preventDefault();
                return;
            }
            else {
                var keyCode = e.keyCode;
                if (keyCode >= 96 && keyCode <= 105) {
                    keyCode -= 48;
                }
                var value = $(this).val();
                value += String.fromCharCode(keyCode);
                value = parseInt(value, 10)
                var maxNumber = $(this).data("maxnumber");
                if (maxNumber) {
                    maxNumber = parseInt(maxNumber);
                    if (value > maxNumber) {
                        e.preventDefault();
                    }
                }
            }
        }
    }

Lógicamente la función podría ser mejor porque no permite copiar ni pegar, no acepta decimales, etc. Está claro que este tipo de funciones son infinitas y según vaya necesitándolo iré agregando funcionalidad a la misma.


La forma de utilizarla sería crear un input type=”text” con un atributo data-maxnumber para establecer el valor máximo permitido y asociar al evento keydown de jQuery, nuestra función.


Por ahora y a falta de plug-in he utilizado un atributo de tipo data-. Si quieres saber más sobre este tipo de atributos puedes leer un post que escribí hace un tiempo. Atributos personalizados en HTML5.


El código de nuestra página sería algo así:

<asp:TextBox ID="txtCodigoCliente" runat="server" data-maxnumber="999"></asp:TextBox>
<script type="text/javascript">
$(document).ready(function () {
   $("#<%=txtCodigoCliente.ClientID %>").on("keydown", numericTextBox);
});
</script>

A partir de aquí, está claro que necesitamos crear un plug-in de jQuery para poder reutilizar al máximo nuestra función.


Siguiendo las indicaciones desde la documentación de jQuery para crear plug-ins http://docs.jquery.com/Plugins/Authoring, el código sería el siguiente:

(function ($) {
    function numericTextBox(e) {
        if (
            e.keyCode == 8 // backspace
            || e.keyCode == 9 // tab
            || e.keyCode == 13 // enter
            || e.keyCode == 27 // escape
            || e.keyCode == 46 // delete
            || (e.keyCode >= 35 && e.keyCode <= 39) // end, home, left arrow, up arrow, right arrow
        ) {
            return;
        }
        else {
            if (!((e.keyCode >= 48 && e.keyCode <= 57) || (e.keyCode >= 96 && e.keyCode <= 105))) {
                // not 0-9, numpad 0-9
                e.preventDefault();
                return;
            }
            else {
                var keyCode = e.keyCode;
                if (keyCode >= 96 && keyCode <= 105) {
                    keyCode -= 48;
                }
                var value = $(this).val();
                value += String.fromCharCode(keyCode);
                value = parseInt(value, 10)
                var maxNumber = $(this).data("maxnumber");
                if (maxNumber) {
                    maxNumber = parseInt(maxNumber);
                    if (value > maxNumber) {
                        e.preventDefault();
                    }
                }
            }
        }
    }
    $.fn.numericTextBox = function () {
        return this.each(function () {
            $(this).on("keydown.numericTextBox", numericTextBox);
        });
    };
})(jQuery);

Ahora ya podemos escribir código jQuery con nuestro plug-in integrado:

$("#<%=txtCodigoCliente.ClientID %>").numericTextBox();

O mejor aún podemos hacer lo siguiente para seleccionar todos los input type=”text” que tenga el atributo data-maxnumber.

$("input[type='text'][data-maxnumber]").numericTextBox();

Finalmente guardamos nuestro código en un fichero llamado jQuery.numericTextBox.js y parecerá un plug-in profesional y todo!!


Un saludo!

3 comentarios:

  1. Se ve bueno. Lo voy a considerar dentro de mi set de tools

    ResponderEliminar
  2. Hola Sergio,

    muy buen artículo. Me lo apunto para futuros usos, aunque me gustaría comentarte que con la función parseInt puedes tener algún disgusto. De esto me di cuenta ayer al hacer una kata en un taller de javascript. Te dejo un ejemplo en jsFiffle

    http://jsfiddle.net/2emUd/

    Como verás parseInt('012') devuelve 10 y no 12 como era de esperar.

    Este comportamiento es porque la cadena empieza por 0 y entonces esta se interpreta como octal. Tienes más información aquí

    http://www.w3schools.com/jsref/jsref_parseint.asp

    Para solucionarlo tan solo debes forzar la base del número, en nuestro caso base 10 (parseInt('012',10)).

    Espero que sirva de ayuda...

    ResponderEliminar
  3. Hola muy buen post, lo probé y me resulta un inconveniente, cuando presiono una letra en el teclado como "primer número" si me la deja escribir, luego si me empieza a validar bien

    ResponderEliminar