a nil value

Blog sobre programación e informática en general (Por Guillermo Zafra)

Browsing Posts tagged web

Quizás en alguna ocasión hayamos querido mostrar una ventana “estilo modal” por encima del resto del formulario. Es algo muy usado en la programación web y que aumenta de forma considerable la usabilidad del interfaz. Sin embargo, en aplicaciones con muchos controles, nos hemos podido encontrar con un desagradable problema, y es que los controles asp.net DropDownList (Select en HTML) ignoran totalmente el estilo z-index de las capas, y como consecuencia aparecen por encima de nuestra ventana modal, estropeando todo el buen aspecto de la aplicación.

Existen dos soluciones conocidas al problema:

La primera, aunque funciona, conlleva la creación de un script que carga mucho trabajo a la aplicación, y según la cantidad de controles que tengamos, puede no ser una posible alternativa.

for (f = 0; f < document.forms.length; f++)
{
    var elements = document.forms[f].elements;
    // looping through all elements on certain form
 
    for (e = 0; e < elements.length; e++)
    {
        if (elements[e].type == "select-one")
        {
            elements[e].style.display = 'none';
        }
    }
}

Este script recorre todos los controles de nuestro formulario, ocultando aquellos que sean del tipo Select. Claro que si tenemos un número finito de este tipo de controles podemos obviar el bucle e ir directamente al grano.

Una vez los tengamos ocultos podemos mostrar nuestra ventana modal sin riesgo a que sea destrozada por los Select, que estarán ocultos.

Por supuesto hay que controlar que, una vez hayamos acabado con la ventana modal, hay que volver a mostrar estos controles usando el mismo sistema.

La segunda alternativa es mas interesante todavía, aunque parece más un “hack” que otra cosa, y desconozco hasta que punto sería compatible con todos los navegadores. Consiste en hacer uso del elemento “iframe”. Este elemento tiene la característica de aparecer siempre por encima de cualquier otro control web, es decir, incluso por encima de los DropDownList. Y diréis, ¿pero eso no sustituye un problema por otro? Nó exactamente, ya que este elemento admite el estilo z-index y ¡lo cumple!.

Vamos, que podemos mostrar una especie de panel separador entre los controles DropDownList y la ventana modal que queramos mostrar tan solo asignandole un z-index inferior al de nuestra ventana.

Primero añadiríamos el iframe dentro de la ventana que vamos a ocultar y mostrar. Tan solo se mostrará cuando mostremos la ventana.

<iframe id="iframe" class="iframeLayer" frameborder="0"></iframe>

Y segundo, añadiremos el estilo correspondiente tal que:

iframe.iframeLayer
{
    left:600px;
    top:300px;
    position: absolute;
    width: 200px;
    height: 100px;
    z-index: 10;
 
}

Hay que tener especial cuidado en especificar exactamente la misma posición y tamaño que la ventana modal. El iframe se mostrará como un area blanca y ocultará todo lo que esté debajo suyo, pero mostrará nuestra ventana siempre que tenga un z-index superior a 10.

El problema de este método es que queramos crear algo más complejo, o por ejemplo crear un fondo transparente, ya que en ese caso, en lugar de crear un iframe para el area de la ventana, tendremos que crear un iframe para el area de cada control DropDownList que tengamos, lo cual ya es otra historia.

La elección es vuestra. Un saludo

Fuente: CodeProject

Supongamos que queremos crear una de esas maravillosas listas dobles de items que nos permita pasar el objeto seleccionado de una lista a otra y viceversa. Esto no tiene ningún secreto, pero si quisieramos que al volver a pasar un item de la segunda lista a la original lo hiciera en la posición en la que estaba originalmente, la cosa se complica un poco.

Esta es una solución. Quizás no la mejor, pero sirve:

Para esto lo primero que tendremos que tener es 3 controles ListBox; dos para las listas de origen y destino, y uno oculto para guardar estáticamente la lista original.

    <asp:ListBox ID="lstOrigen" runat="server" Width="600px" Height ="150px"></asp:ListBox><br /><br />
    <asp:ListBox ID="lstOculto" runat="server" Width="1px" Height ="1px" style="display:none"></asp:ListBox><br />
    <asp:ListBox ID="lstDestino" runat="server" Width="150px" Height ="150px"></asp:ListBox>

Seguidamente, añadiremos nuestro código javascript maravilloso:

       function Add(){
           var lbOrigen = document.getElementById('lstOrigen');
           if(lbOrigen.options.selectedIndex > -1){
                var lbDestino =  document.getElementById('lstDestino'); //obtenemos el contro listbox
                var selectedText = lbOrigen.options[lbOrigen.options.selectedIndex].text;
                var selectedValue = lbOrigen.options[lbOrigen.options.selectedIndex].value;
                for (var i=0; i < lbDestino.options.length; i++) //buscamos coincidencias
                {
                    if (lbDestino.options[i].value.toLowerCase().match(selectedValue.toLowerCase()))
                    {
                                  return false;
                    }
                }
                  var opt = document.createElement("option");
                  opt.text = selectedText;
                  opt.value = selectedValue;
                  lbDestino.options.add(opt);
                  lbOrigen.options.remove(lbOrigen.options.selectedIndex);
           }
        }
        function Remove(){
           var lbDestino = document.getElementById('lstDestino');
           if(lbDestino.options.selectedIndex > -1){
                var lbOculto =  document.getElementById('lstOculto'); //obtenemos el contro listbox
                var lbOrigen =  document.getElementById('lstDestino'); //obtenemos el contro listbox
                var selectedText = lbDestino.options[lbDestino.options.selectedIndex].text;
                var selectedValue = lbDestino.options[lbDestino.options.selectedIndex].value;
                var found = 0; //flag que nos indica si hemos encontrado el item en el listado de destino
                clearListBox(lbOrigen); //limpiamos la lista de origen
                for (var i=0; i < lbOculto.options.length; i++) //buscamos coincidencias del listado original
                {
                    for (var j=0; j < lbDestino.options.length; j++) //buscamos en el listado de añadidos
                    {
                        if (lbOculto.options[i].value.toLowerCase().match(lbDestino.options[j].value.toLowerCase())) //el item fue movido
                        {
                              found = 1; //hemos encontrado el item
                              if (lbOculto.options[i].value.toLowerCase().match(selectedValue.toLowerCase())){
                                 //si el item esta seleccionado lo añadimos al listado de origen
                                 lbOrigen.options.add(crearListItem(selectedText,selectedValue));
                                 break;
                              }
                        }
                    }
                       if (found == 0){ //si no se ha encontrado significa que no está en la lista de destino y debemos añadirlo
                        lbOrigen.options.add(crearListItem(lbOculto.options[i].text,lbOculto.options[i].value));
                       }else{
                         found = 0; //reiniciamos el flag
                       }
 
 
                }
                  lbDestino.options.remove(lbDestino.options.selectedIndex);
           }
        }
 
        function crearListItem(text, value){
                  var opt = document.createElement("option");
                  opt.text = text;
                  opt.value = value;
                  return opt;
        }
        function clearListBox(lb){
            for (var i=lb.options.length-1; i>=0; i--){
                lb.options[i] = null;
            }
            lb.selectedIndex = -1;
        }

Bueno, la función “Add” añadirá el item seleccionado de la lista original a la lista de destino. Para ello comprobamos si hay algun item seleccionado y si este no se encuentra ya en la lista destino, lo añadimos y lo eliminamos del origen.

La función remove es más complicada. Inicialmente limpiará la lista de origen (donde queremos devolver el item a su posición original) y la volvera a reconstruir item por item.

Para ello recorrera la lista oculta(donde tenemos el listado completo de items originales) y buscara coincidencias en la lista de destino. Si no existe coincidencias significa que dicho item no se movió, por lo que lo recuperamos en la lista de origen. Si lo encuentra significa que dicho item lo hemos movido anteriormente, por lo que tenemos que comprobar si es el item que queremos devolver a su posición inicial (esta seleccionado). De ser así, lo añadiremos igualmente a la lista de origen, recuperando asi el item en la posición original (recordad que todo este proceso se realiza en función a la lista oculta), si no está seleccionado, lo obviamos ya que dicho item permanecerá en la lista de destino.

Finalmente eliminamos el item que hemos movido de la lista destino.

Las dos últimas funciones sirven para borrar todos los items de un ListBox y para crear un ListItem con un value y text determinados.

Un saludo

En ocasiones nos encontraremos que tenemos que mostrar un listado de elementos excesivamente largo, y aunque volcarlos en un ListBox sea una solución, no lo es de cara al usuario, que tendrá que desplazarse por todo el control en busqueda del item que quiera seleccionar.

Para solucionarlo podemos hacer uso de un script muy sencillo que nos permitirá buscar y seleccionar automaticamente el primer item que incluya el texto introducido, y conforme vayamos introduciendo más carácteres refinará la busqueda.

Para empezar necesitaremos un control ListBox donde tendremos los elementos a buscar y un HTML TEXT donde realizaremos las busquedas. Es recomendable usar un INPUT TEXT en lugar de un TextBox dado que los eventos de cliente del HTML TEXT son reconocidos en tiempo de diseño, mientras que en el TextBox no, aunque a efectos prácticos obtendremos el mismo resultado.

En el control TEXT añadiremos el evento “onkeyup” para llamar a la función “busqueda”.

<asp:ListBox ID="lstItems" runat="server" Width="154px">
        <asp:ListItem>Alda</asp:ListItem>
        <asp:ListItem>Aldana</asp:ListItem>
        <asp:ListItem>Aldair</asp:ListItem>
        <asp:ListItem>Albano</asp:ListItem>
        <asp:ListItem>Brian</asp:ListItem>
        <asp:ListItem>Cinnia</asp:ListItem>
        <asp:ListItem>Elba</asp:ListItem>
        <asp:ListItem>Fiona</asp:ListItem>
        <asp:ListItem>Ginebra</asp:ListItem>
        <asp:ListItem>Iñigo</asp:ListItem>
        <asp:ListItem>Kenneth</asp:ListItem>
        <asp:ListItem>Marvin</asp:ListItem>
        <asp:ListItem>Oscar</asp:ListItem>
        <asp:ListItem>Quinn</asp:ListItem>
        </asp:ListBox><br />
        <input type="text" id="txtBusqueda" runat="server" onkeyup="busqueda(this)" />

Y a continuación añadiremos el siguiente script:

<script language="javascript" type="text/javascript">
    function busqueda(txt){
        var l =  document.getElementById('lstItems'); //obtenemos el contro listbox
        if(txt.value == ""){
            LimpiarListBox(l); //si el campo de busqueda esta vacio quitamos seleccion
        }else{
            for (var i=0; i < l.options.length; i++) //buscamos coincidencias
            {
                if (l.options[i].value.toLowerCase().match(txt.value.toLowerCase()))
                {
                    l.options[i].selected = true;
                    return false;
                }else{
                    LimpiarListBox(l); //si no se encuentran coincidencias quitamos seleccion
                }
            }
        }
    }
 
    function LimpiarListBox(lb){
        lb.selectedIndex = -1;
    }
</script>

Y voilá, ya tenemos nuestro sistema de búsqueda. Hay que decir que este sistema es muy sencillo pero que se puede complicar todo lo que queramos. Por ejemplo para que busque desde el principio o en una parte de la cadena o value del ListItem. También podemos modificar el evento para que solo busque al perder el foco y mil cosas más.

Si se diera el caso de tener que seleccionar varios items convendría añadir un segundo ListBox de elementos seleccionados y añadir uno a uno los elementos que queramos.

Cuando se trabaja de forma asíncrona con AJAX y UpdatePanels resulta imprescindible implementar procesos para informar al usuario de que se están efectuando actualizaciones en el servidor.

Por defecto, ASP.NET AJAX nos proporcionar el complemento UpdateProgress, que unido a un ScriptManager y un UpdatePanel permiten mostrar cualquier indicador mientras el UpdatePanel esta trabajando asíncronamente.

No obstante el UpdateProgress es limitado si queremos realizar tareas o efectos mas complicados. Por ejemplo posicionar el loader dinamicamente en la pantalla segun lo que se actualice, realizar alguna accion de Jscript antes de comenzar la actualización, o permitir al usuario cancelar el proceso.

Para ello existe un maravilloso y muy simple javascript que controla dos eventos importantísimos de la página; el comienzo y el fin del httprequest.

<script language="javascript" type="text/javascript">
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(
  function(sender, e)
  {
        $get('cargador').style.display="block";
   });
 Sys.WebForms.PageRequestManager.getInstance().add_endRequest(
  function(sender, e)
  {
        $get('cargador').style.display="none";
   });
 
</script>

Donde “cargador” podría ser, por ejemplo:

<div id="cargador" runat="Server" style="display:none">
        <table width="200">
            <tr>
                <td height="50" valign="bottom" align="center">Cargando...</td>
            </tr>
            <tr>
            <td height="50" valign="top" align="center"><img alt="cargando..." src="../img/ajax-loader.gif" /></td>
            </tr>
        </table>
    </div>

add_beginRequest se lanzaría antes de comenzar el evento de solicitar información al servidor y add_endRequest justo despues de terminar todo el proceso.

Para cancelar el Request bastaría con mostrar un boton en el beginRequest que lanzara el siguiente script:

function CancelarPostback() {
    var man= Sys.WebForms.PageRequestManager.getInstance();
    if (man.get_isInAsyncPostBack())
        man.abortPostBack();
    }

Aunque ojo! con este “Cancelar” ya que, si bien cancelara el request y forzando el endRequest, el proceso en el servidor es muy probable que se haya ejecutado ya. Mi consejo es que se utilice unicamente para procesos de lectura y no de escritura.

Un saludo

Bueno, esta es sencilla y fácil de encontrar pero nunca se sabe cuando puede ser útil. Ahora bien, puede confundir al usuario.

<asp:CheckBox runat="server" ID="chkPrueba" onclick="cambiarTextoCheckBox(this);" />

Y la función Javascript:

function cambiarTextoCheckBox(checkbox)
{
  if (checkbox.checked)
    checkbox.nextSibling.innerHTML = 'Activado';
  else
    checkbox.nextSibling.innerHTML = 'Desactivado';
}

Cualquier control web tanto HTML cómo ASP.NET tiene un ID propio que le identifica en una página web y que no puede ser repetido en dicha página. Sin embargo, cuando utilizamos controles de usuario (.ascx) nos encontramos con un problema, y es que podemos tener controles con identificadores repetidos dentro del control de usuario.

Cuando la página se renderiza en completo HTML estos dos controles con el mismo ID no tendrán el mismo, para solucionarlo se utilizan un identificador único que podemos obtener mediante la propiedad UniqueID.

Este ID único se genera de la siguiente manera:

Si en la página principal tuviéramos un control ID “txtMensaje” y con UserControl “PanelMensaje.ascx”.

Y dentro del UserControl PanelMensaje tuvieramos otro control con ID “txtMensaje”, el resultado sería que este último tendría el ID “PanelMensaje$txtMensaje”. Es decir, que todos los controles hijos de PanelMensaje añadirían el prefijo PanelMensaje$ a su id.

Esto es acumulativo, de manera que si anidamos mas controles se identificarán jerárquicamente por los identificadores de los contenedores y separados por el carácter dolar $.

Algo muy común si generamos los controles dinámicamente y los agrupamos por contenedores.

Powered by WordPress Web Design by SRS Solutions © 2010 a nil value Design by SRS Solutions