Moverse entre campos con ENTER en Web Forms

Fecha: 21/Feb/2005 (20/Feb/2005)
Autor: Ernesto Tejeda, [email protected]

Nota 28/Mar/05:
Añadido el código de ejemplo para C# y VB .NET
Nota 17/Abr/2005:
Ahora si que está el código para bajar...
 

 


En este tip usaremos las capacidades de uso de scripts del lado del cliente que incluye ASP.NET . Debo confesar que estoy muy mal acostumbrado al ambiente de las aplicaciones desktop y, más aún, a esas con el estilo del viejo MS-DOS donde los formularios se enfocaban en el uso extenso del teclado y en concreto al uso de la tecla <ENTER> para moverse entre campos de los formularios… me encuentro más natural <ENTER> que Tab y me imagino que muchos otros usuarios y desarrolladores tienen la misma añoranza; por eso quiero compartir con ustedes este tip que uso para lograr el mismo efecto en formularios Web usando ASP.NET y un poco de JavaScript

El objetivo es bastante simple: Se trata de saltar de un campo del formulario Web a otro al presionar la tecla <ENTER>. Para ello vamos a usar una rutina en JavaScript que va a detectar cuando se presione la tecla <ENTER> sobre nuestra ventana de exploración y va a cambiar el control con el foco de entrada al siguiente. El resultado debe ser un código que obtenga esta funcionalidad sin importar los controles del formulario y que podamos usar el mismo código en cualquier formulario Web deseado. Lo que haremos será un arreglo en JavaScript del lado del cliente con los nombres de los controles junto con una variable que nos servirá de índice para señalar cuál es el siguiente control dentro de este arreglo y así pasarle el foco al control indicado. Para esto, al cargar el formulario Web, crearemos este arreglo y lo registraremos del lado cliente usando el método RegisterArrayDeclaration de la página como se muestra a continuación:

        StringBuilder cs = new StringBuilder();
		(…)
		//recorremos todos los controles en el formulario
		foreach(Control c in Page.FindControl(fName).Controls)
		{
			//Nos interesan por ahora sólo los TextBoxes
			if ((c is TextBox) && (((TextBox)c).Enabled) && (!((TextBox)c).ReadOnly))
			{
			//construimos el arreglo o vector paso a paso
			cs.Append(" '"+c.ID+"',");
          (…)
			}
		}
		string holder = cs.ToString().Substring(0, cs.Length -1);
		//registramos la cadena construida como un arreglo de JavaScript
		Page.RegisterArrayDeclaration("controles", holder);

 

Teniendo ya los controles (sólo Textboxes en este caso), registremos el script del lado del cliente que hará que funcione usando RegisterClientScriptBlock.

 
    StringBuilder sb = new StringBuilder();
	sb.Append("<scrip t language=javascript>");
	sb.Append("<  !-- The JavaScript Source!! http://javascript.internet.com -->"); //Inspiración
	sb.Append("nextControl = 0;"); ///nextControl es el índice del próximo 
	sb.Append("Frm = '"+fName+"';");
	sb.Append("ccount ="+control_count.ToString()+";");
	sb.Append("netscape = document.layers;");
	sb.Append("function kPress( eventoPulsaTecla ) ");//Aquí se intercepta el evento en JavaScript
	sb.Append("{  tecla = (netscape) ? eventoPulsaTecla.which : window.event.keyCode;");
	sb.Append("   if (tecla == 13) { ");
	sb.Append("         eval('document.' + Frm + '.' + controles[nextControl] + '.focus()');");
	sb.Append("         eval('if(nextControl < ccount-1) nextControl++; else nextControl = 0;');");
	sb.Append("         return false; } }");
	sb.Append("document.onkeydown = kPress; ");
	sb.Append("if (netscape) document.captureEvents(Event.KEYDOWN);	");
	sb.Append("</script>");	
	Page.RegisterClientScriptBlock("<ENTER>", sb.ToString());  

El script usa el arreglo conteniendo los nombres de los controles para saber cual es el control a darle la atención del teclado mediante la variable nextControl y para que retorne al primero de los controles una vez llegado al último. Nótese el uso de StringBuilder por razones de eficiencia ya que concatenamos varias cadenas de texto. Eso implica el uso del namespace System.Text. Este código funciona pero tiene un pequeño defecto y es que si nos movemos de control usando otro método que no sea mediante la tecla <ENTER>, ya sea con el ratón o con Tab, se pierde la sincronización y retorna justo donde el control que apunte el índice nextControl lo cual se puede resolver "pegando" un poco de JavaScript a cada uno de nuestros controles en el evento onfocus de cada uno para que en la ejecución de ese evento se ajuste el valor de nextControl; eso lo logramos mediante colección Attributes del control como se muestra a continuación.

 //Añadimos un evento adicional para controlar el cambio de focus
((TextBox)c).Attributes.Add("onfocus","javascript:nextControl="+control_count.ToString()+";");

A continuación el código completo del método que hemos desarrollado. Basta con llamarlo durante el evento Load de la página para funcione.

 
protected void RegisterENTERRoutine()
	{
		StringBuilder cs = new StringBuilder();
		string fName="Form1"; ///Nombre del formulario cambiar si es necesario
		int control_count = 0;        
		///recorremos todos los controles en el formulario
		foreach(Control c in Page.FindControl(fName).Controls)
		{
			///Nos interesan por ahora sólo los TextBoxes
			if ((c is TextBox) && (((TextBox)c).Enabled) && (!((TextBox)c).ReadOnly))
			{
			///construimos el arreglo o vector paso a paso
			cs.Append(" '"+c.ID+"',");
			control_count++;
			///Añadimos un evento adicional para controlar el cambio de focus
((TextBox)c).Attributes.Add("onfocus","javascript:nextControl="+control_count.ToString()+";");
			}
		}
		string holder = cs.ToString().Substring(0, cs.Length -1);
		///registramos la cadena construida como un arreglo de JavaScript
		Page.RegisterArrayDeclaration("controles", holder);

		///Ahora el script que dará vida a esto
		StringBuilder sb = new StringBuilder();
		sb.Append("<script language=javascript>"); 
		sb.Append("<!-- The JavaScript Source!! http://javascript.internet.com -->"); ///Inspiración
		sb.Append("nextControl = 0;"); ///nextControl es el índice del próximo 
		sb.Append("Frm = '"+fName+"';");
		sb.Append("ccount ="+control_count.ToString()+";");
		sb.Append("netscape = document.layers;");
		sb.Append("function kPress( eventoPulsaTecla ) ");///Aquí se intercepta el evento
		sb.Append("{  tecla = (netscape) ? eventoPulsaTecla.which : window.event.keyCode;");
			sb.Append("   if (tecla == 13) { ");
			sb.Append("         eval('document.' + Frm + '.' + controles[nextControl] + '.focus()');");
			sb.Append("         eval('if(nextControl < ccount-1) nextControl++; else nextControl = 0;');");
			sb.Append("         return false; } }");
			sb.Append("document.onkeydown = kPress; ");
			sb.Append("if (netscape) document.captureEvents(Event.KEYDOWN);	");
			sb.Append("</script>");	
			Page.RegisterClientScriptBlock("<ENTER>", sb.ToString());
		} 

Espero que les haya parecido interesante este código y cualquier mejora o sugerencia me la hagan saber


Espacios de nombres usados en el código de este artículo:

System...
System.Text

 


Nota del 28/Mar/2005: Añadido el código de ejemplo para C# y VB .NET
Código de C#: ErnestoManuel_FocusEnter_CS.zip 3.56 KB
Código de VB .NET: ErnestoManuel_FocusEnter_VB.zip 3.61 KB

Nota del 17/Abr/2005: Por error los links no estaban bien, ahora si que si... ¡mis disculpas!


ir al índice