none
Validar que TextBox de Grid no esté en blanco RRS feed

  • Pregunta

  • Buen día expertos, tengo el siguiente GridView que lleno mediante un DataTable:

    GridView

    <asp:GridView ID="dgvTransferencia" runat="server" BackColor="White" BorderColor="#999999" BorderStyle="None" BorderWidth="1px" CellPadding="5" AutoGenerateColumns="False" >
    
        <Columns>
    
            <asp:BoundField DataField="Artículo" AccessibleHeaderText="Artículo" HeaderText="Artículo" />
            <asp:BoundField DataField="Descripción" AccessibleHeaderText="Descripción" HeaderText="Descripción" />
            <asp:BoundField DataField="Total" AccessibleHeaderText="Cantidad" HeaderText="Cantidad" />
            <asp:BoundField DataField="Unidad" AccessibleHeaderText="Unidad" HeaderText="Unidad" />
    
            <asp:TemplateField AccessibleHeaderText="Reportar" HeaderText="Reportar">
                <ItemTemplate>
                    <asp:CheckBox ID="chkRow" runat="server" CssClass="ChkBoxClass" />
                </ItemTemplate>
            </asp:TemplateField>
    
            <asp:TemplateField AccessibleHeaderText="Faltante" HeaderText="Faltante">
                <ItemTemplate>
                    <asp:TextBox ID="txtDGVCantidad" runat="server" Text="" TextMode="Number" Width="70" style="text-align: center" Enabled="false" Font-Size="Large"></asp:TextBox>
                </ItemTemplate>
            </asp:TemplateField>
    
        </Columns>
    
        <FooterStyle BackColor="#CCCCCC" ForeColor="Black" />
        <HeaderStyle BackColor="#000084" Font-Bold="True" ForeColor="White" BorderColor="Black" BorderStyle="Solid" BorderWidth="1px" />
        <PagerStyle BackColor="#999999" ForeColor="Black" HorizontalAlign="Center" />
        <RowStyle BackColor="#EEEEEE" ForeColor="Black" HorizontalAlign="Center" VerticalAlign="Middle" />
        <SelectedRowStyle BackColor="#AB8246" Font-Bold="True" ForeColor="White" />
        <SortedAscendingCellStyle BackColor="#F1F1F1" />
        <SortedAscendingHeaderStyle BackColor="#0000A9" />
        <SortedDescendingCellStyle BackColor="#CAC9C9" />
        <SortedDescendingHeaderStyle BackColor="#000065" />
    </asp:GridView> 

    Cuando el usuario marca el checkbox de alguna fila, utilizo el siguiente script para habilitar el textbox de esa fila marcada:

    <script type = "text/javascript">
        $(function () {
            //Enable Disable TextBoxes in a Row when the Row CheckBox is checked.
            $("[id*=chkRow]").bind("click", function () {
    
                //If the CheckBox is Checked then enable the TextBoxes in the Row.
                if (!$(this).is(":checked")) {
                    var td = $("td", $(this).closest("tr"));
                    td.css({ "background-color": "#EEEEEE" });
                    $("input[type=number]", td).attr("disabled", "disabled");
                } else {
                    var td = $("td", $(this).closest("tr"));
                    td.css({ "background-color": "#E1B786" });
                    $("input[type=number]", td).removeAttr("disabled");
                }
            });
        });
    </script>

    Una vez que el usuario llena la tabla, presiona un botón que llama la siguiente función:

    private void DetectarSeleccion()
    {
        int i = 0;
    
        DataTable dt = new DataTable();
        dt.Columns.Add("Artículo");
        dt.Columns.Add("UoM");
        dt.Columns.Add("Faltante");
    
        foreach (GridViewRow row in dgvTransferencia.Rows)
        {
            if((row.Cells[0].FindControl("chkRow") as CheckBox).Checked)
            {
                DataRow dr = dt.NewRow();
                dr["Artículo"] = row.Cells[0].Text;
                dr["UoM"] = row.Cells[3].Text;
                dr["Faltante"] = ((TextBox)dgvTransferencia.Rows[i].FindControl("txtDGVCantidad")).Text;
                dt.Rows.Add(dr);
            }
            i++;
        }
    
        if (dt.Rows.Count > 0)
        {
            dgvCorreo.DataSource = dt;
            dgvCorreo.DataBind();
    
            Shared.tablaCorreo = new DataTable();
            Shared.tablaCorreo = dt.Copy();
    
            PanelComentarios.Visible = true;
        }
        else
            ScriptManager.RegisterStartupScript(this, GetType(), "JCall3", "ShowCustomDialog3();", true);
    }

    Con lo que construyo una tabla que contenga el "resúmen" de lo palomeado y capturado por el usuario.

    Mi pregunta es si hay alguna forma de validar al presionar el botón que los textbox de las filas con el checkbox marcado no se dejen en blanco, ya que requiero que si el usuario marca la casilla, el textbox de esa fila no pueda dejarse vacío. Pero la validación deberá aplicarse sólo a las líneas con la casilla activada.

    Espero haberme explicado bien; cualquier comentario, orientación, ejemplo o enlace serán bienvenidos.

    Gracias de antemano. Saludos cordiales.

    jueves, 15 de marzo de 2018 16:06

Respuestas

  • Primero que nada, me parece curioso que eso le funcione, pues el checkbox está en la celda de índice 4, no de índice 0.

    En cuanto a su pregunta, puede validar de lado de servidor o del lado del cliente (o ambos).  Del lado de servidor le será sencillo:  Utilice FindControl() de la celda índice 5 para ubicar la casilla de texto (tipo TextBox) y examine la propiedad Text.

    Para validar del lado del ciente, el botón de ASP tiene la propiedad OnClientClick que puede usar para asignar la ejecución de una función de JavaScript.  Dicha función validaría los campos.

    Como los ID's de los controles son un problema en ASP.net webforms, tal vez lo mejor sería aprovechar su código actual para ir recolectando las casillas de texto.  Necesitaremos una variable global.

    Adicione el siguiente script a la página:

    <script type="text/javascript" language="javascript">
        var cajasFaltantes = [ ];
    </script>

    Eso crea una colección vacía, lista para rellenarse.  Luego modificamos su código actual para insertar y eliminar las cajas de la colección.

    <script type = "text/javascript">
        $(function () {
            //Enable Disable TextBoxes in a Row when the Row CheckBox is checked.
            $("[id*=chkRow]").bind("click", function () {
    
                //If the CheckBox is Checked then enable the TextBoxes in the Row.
                if (!$(this).is(":checked")) {
                    var td = $("td", $(this).closest("tr"));
                    td.css({ "background-color": "#EEEEEE" });
                    var caja = $("input[type=number]", td);
                    caja.attr("disabled", "disabled");
                    var index = cajasFaltantes.indexOf(caja);
                    cajasFaltantes.splice(index, 1);
                } else {
                    var td = $("td", $(this).closest("tr"));
                    td.css({ "background-color": "#E1B786" });
                    var caja = $("input[type=number]", td);
                    caja.removeAttr("disabled");
                    cajasFaltantes.push(caja);
                }
            });
        });
    </script>

    Eso mantendría la colección de casillas de texto al día, creo yo.

    Ahora hay que hacer la función que recorre la colección:

    function ValidarFaltantes() {
        $.each(cajasFaltantes, function(index, caja) {
            if (!caja.val()) {
                //La casilla de texto está vacía.  Animar la página para mostrarla o lo que sea.
                ...
                return false; //Deshabilita el postback.
            }
        });
        //Si llegamos a este punto, todo bien.  Permitimos el postback.
        return true;
    }

    Este método debería servirle si no hace más de un postback.  Si hiciera más de un postback, podría ser que ya hayan checkboxes marcados, entonces la colección cajasFaltantes necesitaría ser inicializada con las casillas de texto que ya deberían venir habilitadas del postback.  Pero con suerte ese no es su caso.


    Jose R. MCP
    Code Samples


    jueves, 15 de marzo de 2018 16:40
    Moderador

Todas las respuestas

  • Primero que nada, me parece curioso que eso le funcione, pues el checkbox está en la celda de índice 4, no de índice 0.

    En cuanto a su pregunta, puede validar de lado de servidor o del lado del cliente (o ambos).  Del lado de servidor le será sencillo:  Utilice FindControl() de la celda índice 5 para ubicar la casilla de texto (tipo TextBox) y examine la propiedad Text.

    Para validar del lado del ciente, el botón de ASP tiene la propiedad OnClientClick que puede usar para asignar la ejecución de una función de JavaScript.  Dicha función validaría los campos.

    Como los ID's de los controles son un problema en ASP.net webforms, tal vez lo mejor sería aprovechar su código actual para ir recolectando las casillas de texto.  Necesitaremos una variable global.

    Adicione el siguiente script a la página:

    <script type="text/javascript" language="javascript">
        var cajasFaltantes = [ ];
    </script>

    Eso crea una colección vacía, lista para rellenarse.  Luego modificamos su código actual para insertar y eliminar las cajas de la colección.

    <script type = "text/javascript">
        $(function () {
            //Enable Disable TextBoxes in a Row when the Row CheckBox is checked.
            $("[id*=chkRow]").bind("click", function () {
    
                //If the CheckBox is Checked then enable the TextBoxes in the Row.
                if (!$(this).is(":checked")) {
                    var td = $("td", $(this).closest("tr"));
                    td.css({ "background-color": "#EEEEEE" });
                    var caja = $("input[type=number]", td);
                    caja.attr("disabled", "disabled");
                    var index = cajasFaltantes.indexOf(caja);
                    cajasFaltantes.splice(index, 1);
                } else {
                    var td = $("td", $(this).closest("tr"));
                    td.css({ "background-color": "#E1B786" });
                    var caja = $("input[type=number]", td);
                    caja.removeAttr("disabled");
                    cajasFaltantes.push(caja);
                }
            });
        });
    </script>

    Eso mantendría la colección de casillas de texto al día, creo yo.

    Ahora hay que hacer la función que recorre la colección:

    function ValidarFaltantes() {
        $.each(cajasFaltantes, function(index, caja) {
            if (!caja.val()) {
                //La casilla de texto está vacía.  Animar la página para mostrarla o lo que sea.
                ...
                return false; //Deshabilita el postback.
            }
        });
        //Si llegamos a este punto, todo bien.  Permitimos el postback.
        return true;
    }

    Este método debería servirle si no hace más de un postback.  Si hiciera más de un postback, podría ser que ya hayan checkboxes marcados, entonces la colección cajasFaltantes necesitaría ser inicializada con las casillas de texto que ya deberían venir habilitadas del postback.  Pero con suerte ese no es su caso.


    Jose R. MCP
    Code Samples


    jueves, 15 de marzo de 2018 16:40
    Moderador
  • Buen día José, primero que nada una disculpa por la demora en responder, este fin tuvimos un puente vacacional en México y hasta hoy pude revisarlo.

    Te comento que agregué el código que me proporcionas y le incluí un alert(), se lo asigné al clic del botón desde codebehind de la siguiente forma:

    ScriptManager.RegisterStartupScript(this, GetType(), "empty", "ValidarFaltantes();", true);

    Sin embargo, no sucede nada al dar clic. Seguí la información como me indicas, probablemente esté haciendo algo mal.

    Gracias de antemano por tu asistencia! Recibe un cordial saludo.

    martes, 20 de marzo de 2018 19:10
  • La función de ValidarFaltantes que yo escribí no va en un startup script.  Va en el OnClientClick de un botón ASP.

    <asp:Button id="elID" OnClientClick="return ValidarFaltantes();" .... />


    Jose R. MCP
    Code Samples


    martes, 20 de marzo de 2018 22:54
    Moderador
  • Muchas gracias por tu respuesta José, y efectivamente agregué el evento en el botón y funcionó perfecto.

    Espero no estar abusando de tu paciencia, sólo tengo una última pregunta, a ese botón le tengo un evento OnClick, y se ejecuta junto con ValidarFaltantes(), puedo condicionar mi otra función para que sólo se ejecute si ValidarFaltantes() regrese true, pero si regresa false sólo aparezca la alerta?

    Algo así:

    function ValidarFaltantes() {
        $.each(cajasFaltantes, function(index, caja) {
            if (!caja.val()) {
            //La casilla de texto está vacía.
            alert("Se ha dejado una casilla vacía.");
            return false; //Deshabilita postback.
            }
        });
    
        //Ejecutar aquí la funcion anterior
        Funcion();
    
        return true;
    }

    Lo pongo de esta forma porque no conozco nada de javascript, realmente no sé si sea lo correcto ejecutar la función desde esa parte del código, o si se validaría de alguna forma desde codebehind.

    Gracias de antemano!

    miércoles, 21 de marzo de 2018 0:08
  • Tal y como le escribí la función y tal y como la puse en el botón de ASP debería automáticamente cancelar el postback (y por lo tanto, el evento Click en el servidor) del botón si la función devuelve false, que es cuando hay casillas de texto vacías.  ¿Dice que no le funciona?

    Jose R. MCP
    Code Samples

    miércoles, 21 de marzo de 2018 0:24
    Moderador
  • Buen día José, pues le comento que al dar clic en el botón de ASP se ejecuta la función ValidarFaltantes() y aparece la alerta en la página, pero luego de eso también se ejecuta el resto

    <asp:Button ID="btnEnviarComentarios" runat="server" Text="Reporte" OnClick="btnEnviarComentarios_Click" OnClientClick="return ValidarFaltantes();" />

    Lo que tengo en el evento clic es la llamada a otra función de esta forma:

    protected void btnEnviarComentarios_Click(object sender, EventArgs e)
    {
        DetectarSeleccion();
    }

    Se podrá de alguna forma (con variable global u otra posible solución) condicionar DetectarSeleccion() dependiendo del valor devuelto por ValidarFaltantes()?

    Gracias de antemano por su tiempo y apoyo.

    miércoles, 21 de marzo de 2018 14:52