DNM+ Online
dotnetmania 2.0
Emitir código JavaScript desde WebForms y controles Web personalizados
A pesar de la profusión de novedades y mejoras aportadas por ASP.NET, existen situaciones cuya resolución sigue siendo aconsejable realizar utilizando rutinas de script en el navegador cliente. En el presente artículo explicamos cómo abordar este tipo de escenarios desde ASP.NET.

La dependencia del lado cliente

La llegada de ASP.NET al mundo del desarrollo de aplicaciones para Internet ha supuesto una considerable mejora con respecto al modelo de programación ofrecido por ASP 3 (también conocido como ASP clásico), que imperaba anteriormente. Los cambios en dicho modelo han sido cuantiosos y profundos, contribuyendo entre otros muchos aspectos a la consecución de un código más efectivo en un menor espacio de tiempo. No cabe duda de que el paradigma de desarrollo propuesto por ASP.NET es a todas luces más óptimo que el disponible con la anterior versión de la plataforma de desarrollo Web de Microsoft, residiendo uno de sus puntos destacables en el conjunto de controles Web, los cuales ofrecen un abanico de posibilidades de programación más amplio y rico en métodos, propiedades y eventos que los tradicionales controles HTML de ASP clásico; no obstante, como todos sabemos, también podemos seguir utilizando estos últimos en formularios ASP.NET. Podemos programar gran parte del comportamiento y funcionalidad de los nuevos controles Web desde el lado del servidor, dado que su arquitectura está diseñada para ser gestionada en esta parte del flujo de proceso de la aplicación, lo que ofrece una potencia inusitada con respecto a la programación Web empleando ASP clásico. Sin embargo, el hecho de que ahora tengamos una mayor capacidad de control del lado servidor en nuestras aplicaciones, no quiere decir que esto sea la panacea que vaya a resolver todos nuestros problemas de desarrollo, ni tampoco resulta conveniente su uso desmesurado, ya que seguirán existiendo operaciones cuyo tratamiento sea más adecuado efectuarlo en el lado cliente, dado que su gestión en el servidor provocaría una pérdida de rendimiento. Es por ello que derivar la ejecución de ciertas tareas para que se procesen en el navegador cliente sigue siendo un factor primordial en aras de conseguir una aplicación equilibrada en lo que al consumo de recursos se refiere, y ágil en cuanto a su ejecución. De esta manera se descarga en muchos casos al servidor de un importante número de operaciones que de otro modo tendría que soportar, o que en determinadas situaciones ni siquiera sería viable su ejecución en el servidor por cuestiones de eficacia de la aplicación. Por este motivo, tal y como reza el título del artículo, vamos a describir los mecanismos con los que cuenta ASP.NET para la generación de código de script en el navegador cliente, y más concretamente JavaScript, ya que representa el lenguaje de script más ampliamente utilizado en el desarrollo de aplicaciones para Internet. Como navegador Web empleado en la demostración de los diversos ejemplos utilizaremos Internet Explorer. También haremos un repaso de las técnicas utilizadas para asociar el código JavaScript que generemos con los eventos de los controles de nuestros formularios Web, y un pequeño truco para facilitar la generación de este tipo de código desde el servidor. Dado que este es un artículo que versa sobre cómo aplicar JavaScript, se asume por parte del lector un conocimiento al menos básico de este lenguaje. Todos los casos tratados se ilustrarán a través de ejemplos repartidos en dos soluciones de Visual Studio .NET, que el lector puede descargar, como material de apoyo para este artículo, desde la dirección www.dotnetmania.com. Comencemos pues por la primera de estas soluciones, EjArticASPNETJS, en la que podemos encontrar un proyecto de igual nombre con varios WebForms, que ilustran algunos de los ejemplos de los próximos apartados. El formulario de entrada de este proyecto, Inicio.aspx, dispone de varios botones que nos darán paso a cada uno de los WebForm de ejemplo. Al estilo antiguo Si nos encontramos en la situación de ser un programador de ASP clásico que necesita migrar hacia ASP.NET, debemos saber que la creación de código JavaScript podemos seguir realizándola en el modo al que ya estamos acostumbrados, lo que facilita la curva de aprendizaje en lo que a este particular respecta. Para ello crearemos el formulario WebForm1, y en modo de diseño situaremos dos controles Input de tipo texto, cuya finalidad será la de comprobar la cantidad de caracteres que hemos escrito en uno de los controles, mostrando dicho número en el otro. Seguidamente accederemos al código HTML del formulario y entre las etiquetas <head></head> escribiremos nuestro código JavaScript, utilizando, naturalmente, las etiquetas <script></script>. Este código consistirá en una función que será llamada al producirse el evento onblur en uno de los controles, y que efectuará el cálculo anteriormente mencionado, como vemos en el fuente 1. Terminada la creación de este formulario, lo ejecutaremos, comprobando cómo el código cliente que hemos escrito se ejecuta al desencadenarse el evento correspondiente. Puede darse también el caso de que tengamos un elevado número de funciones en JavaScript, parte de las cuales son de propósito general, que necesitaremos reutilizar en la mayoría de los formularios de la aplicación. Para no tener que volver a repetir esas funciones en todos los formularios, podemos crear un archivo que contenga este código JavaScript de uso general, y referirnos a él usando el atributo src de la etiqueta <script>, como hacemos en el formulario WebForm2 del proyecto. Véase el fuente 2. Lo que hemos hecho aquí ha sido añadir el archivo FuncionesVarias.js al proyecto, y escribir en él las funciones PasarMayusculas() y CambiarColor(), para después conectarlas mediante el evento onblur de los controles del formulario txtNombre y txtCiudad. Generación de código script al estilo ASP.NET Dejando a un lado ya la antigua técnica de generación de JavaScript, pasemos a describir los mecanismos de que dispone ASP.NET para realizar todo el proceso de emisión de este tipo de código desde el lado servidor. Partiendo del hecho de que vamos a trabajar con controles Web, debido a las múltiples ventajas que presentan, no es posible, dada la naturaleza de estos controles, efectuar la conexión entre una función JavaScript y un evento del control de la misma forma que veíamos en el apartado anterior con los controles HTML. Ahora debemos utilizar un mecanismo distinto, consistente en escribir el código JavaScript en el code-behind del WebForm, procediendo a su emisión hacia el navegador mediante el método RegisterClientScriptBlock de la clase Page, que tiene la siguiente sintaxis: Page.RegisterClientScriptBlock(Clave, CodigoScript) A continuación describimos los parámetros de este método: •    Clave: Cadena que identifica de modo unívoco al bloque de código JavaScript que estamos registrando/generando para el formulario. Esto nos permite poder utilizar varias veces este método para registrar diferentes bloques de código script, cada uno con su correspondiente identificador. •    CodigoScript: Cadena que contiene el bloque de código JavaScript que vamos a registrar/enviar al navegador Web desde el code-behind. Como ejemplo de esta técnica de creación de código en el cliente Web, el formulario WebForm3 de nuestro proyecto de prueba contiene, en su método Load, las instrucciones para generar nuestro código de script pertinente y registrarlo con Register­ClientScript­Block, como vemos en el fuente 3. Al ejecutar este WebForm, si accedemos a la opción "Ver código fuente" en el navegador, comprobaremos como allí aparece el código script que hemos emitido desde el code-behind de la página, todo ello sin necesidad de haber manipulado directamente el HTML del WebForm. La única pega que podríamos achacar a este resultado sería que el código JavaScript generado se dispone en una línea única, lo que dificulta su lectura en el navegador, y lo que es más grave, cuando existe una gran cantidad de este código se pueden producir errores en su ejecución. Para remediar este inconveniente tan sólo hemos de añadir, desde el code-behind, un salto de línea de forma explícita a cada una de las líneas del script, utilizando la enumeración/miembro ControlChars.CrLf, como vemos en el fuente 4. Para añadir saltos de línea también podemos utilizar la clase/propiedad Environment.NewLine, que devuelve una cadena con los caracteres de nueva línea para la plataforma de ejecución actual. Las operaciones que acabamos de practicar simplemente crean código de script y lo depositan en el navegador Web, no ejecutan por sí mismas una de estas funciones JavaScript que hemos generado en el navegador. Nos queda pendiente pues una parte muy importante del proceso: conectar una función de script con el evento del control que deberá ejecutarla. Para lograr este objetivo debemos tomar el control Web que necesitamos conectar con el código JavaScript, y añadir a su colección de atributos el nombre del evento y la función de script que actuará como manipulador de dicho evento cuando sea desencadenado. El fuente 5, que también escribiremos en el evento Load del formulario, ilustra el modo de llevar a cabo esta acción. La colección Attributes, disponible para todos los controles Web, permite que al ser creado en el navegador el código HTML correspondiente al control, se generen también, dentro de las etiquetas del control, determinados atributos que no están disponibles a través de las propiedades de la clase del control. Como puede comprobar el lector, en este caso, empleamos la mencionada colección para producir el código HTML que asigna a un evento del control una función del script. Para el CheckBox chkMayMin de nuestra página, el HTML resultante sería el siguiente: <input    id="chkMayMin" type="checkbox" name="chkMayMin" onclick="CambiarMayMin()" /> De esta forma, cuando ejecutemos la página WebForm3, cada vez que marquemos o desmarquemos el CheckBox, se ejecutará la función CambiarMayMin en respuesta al evento onclick de este control. Si a pesar de lo anterior, seguimos prefiriendo escribir nuestro código de script dentro del HTML del formulario, es totalmente factible hacerlo (aunque no sea la práctica recomendada), ya que la colección Attributes de los controles Web no distingue si el código JavaScript ha sido escrito directamente en el HTML del WebForm o desde su code-behind. Depurando nuestro código JavaScript Si necesitamos saber con una mayor exactitud cuándo se ejecuta nuestro código de script en el navegador Web, podemos hacer que el depurador de Visual Studio .NET supervise dicho código en tiempo de ejecución; para ello debemos seguir unos sencillos pasos que explicamos a continuación. En primer lugar abriremos Internet Explorer, seleccionando su opción de menú "Herramientas" + "Opciones de Internet". A continuación haremos clic en la pestaña "Opciones avanzadas", y dentro de ésta, desmarcaremos la casilla con el título "Deshabilitar depuración de secuencias de comandos", como vemos en la figura 1. Tras aceptar este cuadro de diálogo pasaremos a la función que necesitemos depurar de nuestro bloque de script, y dentro de su código situaremos la instrucción debugger, sin finalizar la línea con punto y coma, como vemos en el fuente 6. Al cargarse ahora en el navegador la página que contiene esta función, cuando la misma sea ejecutada se producirá una parada en el flujo de ejecución, entrando en acción el depurador de igual forma que si estuviéramos depurando el code-behind de una página ASPX. Dentro de este contexto podremos evaluar expresiones, visualizar el contenido de variables, propiedades de controles, etc. La figura 2 muestra un ejemplo de esta situación. Ejecutando un bloque de script durante la carga de la página Durante el proceso de creación del WebForm podemos emitir un bloque de código de script para que sea ejecutado durante esta fase inicial de creación de la página. Todo lo que tenemos que hacer es escribir dicho bloque sin que se encuentre contenido dentro de una función JavaScript, como vemos en el fuente 7. Esta práctica sufre empero de un inconveniente. Supongamos que nos encontramos diseñando un formulario que tiene un control DropDownList con la lista de meses del año, y queremos que al comenzar la ejecución de dicho formulario se compruebe cuál es el mes correspondiente a la fecha actual, dejándolo como elemento seleccionado en la lista antes de presentar la página al usuario. Ante estos requerimientos hemos de tener presente que el método Page.RegisterClientScriptBlock genera el JavaScript justamente después de la etiqueta HTML de apertura del WebForm: <form>, lo quiere decir que si usamos este método para incluir un bloque de código que intente manipular uno de los controles del formulario, se producirá un error porque al ser ejecutado el script todavía no se habrán creado los controles del WebForm. La solución a este problema la encontramos en el método Page.Regis­ter­StartupScript, que también emite código de script al navegador, pero situándolo en este caso justo antes de la etiqueta HTML que cierra el WebForm: </form>. El modo de uso de este método es igual que RegisterClientScriptBlock, es decir, debemos pasar al método una cadena que será el identificador único del bloque de código, y otra cadena conteniendo el código JavaScript. Veamos este método en acción dentro del evento Load de la página WebForm4 (fuente 8). Ahora ya no se producirán errores en este sentido, puesto que al ser ejecutado el JavaScript, los controles del formulario ya estarán creados, como vemos a continuación, en el código HTML de la página accesible desde el navegador (fuente 9). Generación de código JavaScript desde controles Web personalizados Cuando desarrollamos controles Web propios, en la gran mayoría de casos también necesitaremos que los mismos emitan código de script para el navegador Web en el que tengan que ejecutarse. Es por ello, que las capacidades de creación de JavaScript en ASP.NET están disponibles para ser usadas tanto desde WebForms como desde controles Web. Como ejemplo para este tipo de casos usaremos la solución EjArticCtlASPNETJS, que también podemos descargar de www.dotnetmania.com. Esta solución la compone el proyecto MisControlesWeb, que consiste en una librería de clases conteniendo un par de controles Web para las diversas pruebas de generación de scripts, y un proyecto con el mismo nombre de la solución, que usaremos como banco de pruebas de los controles personalizados. El primer control con el que vamos a tratar será CajaNúmero, una clase que hereda de WebControl, y que en tiempo de ejecución crea un TextBox que sólo permite escribir números. Como es natural, dadas las características de nuestro artículo, el elemento de este control que va a comprobar si su contenido es exclusivamente numérico será un bloque de código JavaScript. Un control no puede, por sí mismo, emitir el código de script que necesite depositar en el navegador, es decir, carece de los métodos RegisterXXX que veíamos en ejemplos anteriores. Sin embargo, un control sí dispone de la propiedad Page, que representa al WebForm que lo contiene, y por mediación de esta propiedad puede acceder a los métodos RegisterXXX de su formulario para crear los bloques de código de script que necesite. Podemos realizar esta tarea reemplazando el método OnPreRender en la clase de nuestro control, como vemos en el fuente 10. El objeto oCaja representa al TextBox que mostrará nuestro control personalizado, y actúa como control constituyente del control Web principal. Para instanciar y generar este TextBox, debemos reemplazar los método CreateChildControls y Render, respectivamente, añadiendo el código que se ocupe de dichas tareas, como vemos en el fuente 11. De esta forma ya podemos utilizar el control en el WebForm de pruebas, donde veremos que sólo nos permitirá introducir números. Comprobar si un bloque de código script ya ha sido registrado Como ya sabemos, el primer parámetro de los métodos Page.RegisterXXX consiste en una cadena que funciona como identificador del bloque de código que estamos generando en el navegador, lo que impide que registremos en más de una ocasión un bloque de código script con el mismo identificador. Pongamos como ejemplo el fuente 12. Cuando este code-behind sea ejecutado, el código JavaScript generado en el navegador sólo corresponderá a la función Primera(), ya que al intentar registrar el siguiente bloque de script, como también estamos utilizando el identificador "CodJS", ASP.NET detectará que ya ha sido registrado un script con el mismo identificador, ignorando este último intento de registro. En este preciso momento se estará preguntando, estimado lector, acerca de la utilidad de lo que acabamos de explicar, y ciertamente, observada desde el contexto de un WebForm, esta situación no reviste mayores problemas si simplemente registramos todo nuestro código JavaScript con una única llamada a cada uno de los métodos RegisterXXX. Donde realmente este escenario cobra importancia es cuando nos encontramos desarrollando nuestros propios controles Web, sobre todo aquellos que pueden necesitar una considerable cantidad de código de script. Debemos tener presente que si añadimos a un WebForm varias copias de nuestro control, cada una de estas instancias pasará por las líneas de código que generan el bloque de JavaScript, pero sólo será en la primera ocasión en que se ejecuten, cuando se emita el consabido código de script hacia el navegador, mientras que en el resto de ocasiones en que el flujo de la aplicación pase por este mismo punto, la llamada a los métodos RegisterXXX no tendrá resultado alguno, consumiendo inútilmente un precioso tiempo de proceso y recursos. Para optimizar esta situación, la clase Page proporciona los métodos IsClient­ScriptBlockRegistered e IsStartup­Script­­Registered, que sirven para confirmar si un bloque de código script ya ha sido registrado utilizando los métodos RegisterClientScriptBlock o Register­StartupScript respectivamente. Ambos métodos reciben como parámetro una cadena que representa al identificador del bloque de código a comprobar, y devuelven un valor lógico que indica si ya existe en la página un script con ese identificador. Aplicando esta técnica al control CajaNumero, deberemos modificar ligeramente el método OnPreRender del modo que muestra el fuente 13. Empleando macros para automatizar la preparación del código JavaScript Como hemos mencionado en un apartado anterior, cuando necesitamos añadir una gran cantidad de código de script a un WebForm podemos escribirlo en un archivo .js aparte, y establecer una referencia al mismo desde el HTML del formulario, utilizando el atributo src de la etiqueta <script>. Esta práctica puede resultar un problema cuando el código JavaScript a generar pertenece a un control Web personalizado, ya que en ese caso, además del ensamblado que contiene el control, debemos proporcionar el archivo con su código de script asociado. En resumen, se trata de un modo de trabajo poco efectivo. Cuando diseñamos y desarrollamos un control propio debemos procurar que su funcionamiento sea lo más autónomo posible; esto quiere decir que si debe generar código de script, tiene que hacerlo el propio control desde el interior de su clase utilizando los métodos RegisterXXX, lo cual puede llegar a resultar un tanto farragoso por la conveniencia, ya explicada en anteriores ejemplos, de concatenar las líneas de código en una variable y añadir los correspondientes saltos de línea. ¿No sería estupendo poder escribir el código JavaScript de igual modo que lo hacemos con el código "normal" del control, es decir, sin tener que concatenar cada línea a una variable que lo contenga ni añadirle el salto de línea final?. Pues bien, esto es posible si recurrimos a una potente herramienta que nos proporciona el entorno de Visual Studio .NET: las macros. Gracias a una macro, el programador puede dedicarse a escribir exclusivamente el código de script, y encomendar a la macro el trabajo pesado de concatenar todo ese código en una variable, y añadir los caracteres especiales de salto de línea. Procedamos pues. Primeramente añadiremos al proyecto un nuevo control con el nombre CajaColor, que consistirá en una caja de texto, cuyo color de fondo y contenido cambiará en base a determinadas circunstancias. A continuación también agregaremos al proyecto un archivo con el nombre GeneracionCodigoJS.js, en el que escribiremos las funciones JavaScript que conectaremos con los eventos del control. El fuente 14 muestra una función encargada de cambiar el color de fondo de la caja, según la cantidad de caracteres que esta contenga. El siguiente paso consiste en seleccionar el menú de Visual Studio .NET "Herramientas" + "Macros" + "Explorador" de macros, que abrirá la ventana "Explorador de macros", dentro de la cual expandiremos sus nodos de la siguiente forma: "Macros" + "MyMacros" + "Module1". Ver la figura 3. Haciendo clic derecho sobre el nodo Module1, seleccionaremos la opción "Editar", con la que entraremos en el entorno de desarrollo de macros (IDE) de VS.NET, quedando situados dentro del editor de código de macros, en el que escribiremos la macro TransfCodigoJSEnBloque, que no es otra cosa que un procedimiento Sub que se ejecuta bajo un contexto muy particular dentro del entorno de desarrollo. El objetivo de esta macro consiste precisamente en realizar el trabajo que antes hacíamos manualmente, es decir, tomar el código de script y concatenarlo a una variable, incluyendo los caracteres especiales de salto de línea. Debido a que un tratamiento exhaustivo de las macros es algo que queda fuera del ámbito de este artículo, hemos proporcionado las oportunas explicaciones dentro del código para que el lector sepa lo que está ocurriendo en cada momento. Prometemos abordar el interesante tema de las macros en un próximo artículo, veamos ahora el contenido de la macro en el fuente 15. Finalizada la creación de la macro volveremos al proyecto de los controles Web, y nos situaremos en el código de la función JavaScript CambiarColor. Desde aquí podemos ver en la ventana "Explorador de macros" la macro TransfCodigoJSEnBloque recién creada; haciendo doble clic sobre la misma se ejecutará, aplicando la transformación sobre nuestro código de script que vemos en el fuente 16. A continuación tomaremos el código resultante tras la ejecución de la macro y lo situaremos como un método del control, al que llamaremos en el momento de registrar los bloques de código de script, lo cual, en nuestro ejemplo, hacemos desde el método OnPreRender, como vemos en el fuente 17. Una de las ventajas en el empleo de esta técnica consiste en que mantenemos fácilmente la indentación del código de script generado, lo que facilita su lectura desde la opción de visualizar código del navegador. Conectando eventos y código JavaScript desde el método AddAttributesToRender Como punto final a este artículo, para conectar los eventos cliente de nuestro control CajaColor con las funciones JavaScript, vamos a utilizar una nueva técnica de trabajo que consiste en reemplazar el método AddAttributesToRender, el cual es llamado durante la creación del control. En este método podemos centralizar todas las instrucciones relacionadas con la creación de atributos para el control, es decir, la conexión entre los diferentes eventos desencadenados en el lado cliente por el control, y las funciones de script que se ejecutarán en respuesta a dichos eventos. El fuente 18 muestra un ejemplo de uso de este método. AddAttributesToRender recibe un parámetro de tipo HtmlTextWriter, que usaremos para asociar los eventos y el código de script llamando a su método AddAttribute. AddAttribute, por otra parte, recibe dos parámetros: el primero lo utilizamos para especificar el nombre del evento a tratar, bien como una cadena de caracteres o mediante uno de los miembros de la enumeración HtmlTextWriterAttribute; el segundo parámetro es una cadena con el nombre de la función de script que actuará como manipulador del evento. <script> Finalizamos </script> Nuestro periplo termina aquí, no sin antes agradecer al lector la atención que nos haya dedicado, confiando en que todas las experiencias aquí vertidas puedan serle útiles en su quehacer diario como noble artesano del código.

blog comments powered by Disqus
autor
referencias