Compartir a través de


Agregar la confirmación del cliente al eliminar (VB)

de Scott Mitchell

Descargar PDF

En las interfaces que hemos creado hasta ahora, un usuario puede eliminar datos accidentalmente haciendo clic en el botón Eliminar cuando pretendía hacer clic en el botón Editar. En este tutorial agregaremos un cuadro de diálogo de confirmación del lado cliente que aparece cuando se haga clic en el botón Eliminar.

Introducción

En los últimos tutoriales hemos visto cómo usar nuestra arquitectura de aplicaciones, ObjectDataSource y los controles web de datos en concierto para proporcionar funcionalidades de inserción, edición y eliminación. Las interfaces de eliminación que hemos examinado hasta ahora han consistido en un botón Eliminar que, al hacer clic, provoca un postback e invoca el método Delete() de ObjectDataSource. Entonces, el método Delete() invoca el método configurado desde la Capa de Lógica de Negocios, que propaga la llamada hacia la Capa de Acceso a Datos, emitiendo la instrucción real DELETE a la base de datos.

Aunque esta interfaz de usuario permite a los visitantes eliminar registros a través de los controles GridView, DetailsView o FormView, carece de confirmación cuando el usuario hace clic en el botón Eliminar. Si un usuario hace clic accidentalmente en el botón Eliminar cuando quería hacer clic en Editar, el registro que pretendía actualizar se eliminará en su lugar. Para evitar esto, en este tutorial agregaremos un cuadro de diálogo de confirmación del lado cliente que aparece cuando se haga clic en el botón Eliminar.

La función JavaScript confirm(string) muestra su parámetro de entrada de cadena como texto dentro de un cuadro de diálogo modal que viene equipado con dos botones: Aceptar y Cancelar (vea la figura 1). La confirm(string) función devuelve un valor booleano dependiendo de qué botón se hace clic (truesi el usuario hace clic en Aceptar y false , si hace clic en Cancelar).

El método confirm(string) de JavaScript muestra un cuadro de mensaje modal, Client-Side

Figura 1: El método JavaScript confirm(string) muestra un cuadro de mensaje modal, Client-Side

Durante un envío de formulario, si se devuelve un valor de false desde un controlador de eventos del lado cliente, se cancela el envío del formulario. Con esta característica, podemos hacer que el controlador de eventos del lado onclick cliente del botón Eliminar devuelva el valor de una llamada a confirm("Are you sure you want to delete this product?"). Si el usuario hace clic en Cancelar, confirm(string) devolverá false, lo que hará que el envío del formulario se cancele. Sin postback, el producto en el que se hizo clic en el botón Eliminar no se eliminará. Sin embargo, si el usuario hace clic en Aceptar en el cuadro de diálogo de confirmación, el postback continuará sin tener en cuenta y se eliminará el producto. Consulte Uso del método de JavaScript para confirm() controlar el envío de formularios para obtener más información sobre esta técnica.

Agregar el script necesario del lado del cliente difiere ligeramente cuando se utilizan plantillas en comparación con el uso de un CommandField. Por lo tanto, en este tutorial veremos un ejemplo de FormView y GridView.

Nota:

Con técnicas de confirmación del lado cliente, como las descritas en este tutorial, se supone que los usuarios visitan con exploradores que admiten JavaScript y que tienen JavaScript habilitado. Si alguna de estas suposiciones no es cierta para un usuario determinado, al hacer clic en el botón Eliminar se producirá inmediatamente una devolución (no se muestra un cuadro de mensaje de confirmación).

Paso 1: Crear un FormView que admita la eliminación

Empiece agregando un FormView a la ConfirmationOnDelete.aspx página de la EditInsertDelete carpeta, enlazando a un nuevo ObjectDataSource que extraiga la información del producto a través del método de la ProductsBLL clase s GetProducts() . Configure también ObjectDataSource de modo que el método de la clase ProductsBLL se asigne al método de la clase de ObjectDataSource DeleteProduct(productID), y que el método de Delete() se asigne a él; asegúrese de que las pestañas desplegables INSERT y UPDATE estén establecidas en (None). Por último, active la casilla Habilitar paginación en la etiqueta inteligente FormView s.

Después de estos pasos, el nuevo marcado declarativo objectDataSource tendrá un aspecto similar al siguiente:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    DeleteMethod="DeleteProduct" OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProducts" TypeName="ProductsBLL">
    <DeleteParameters>
        <asp:Parameter Name="productID" Type="Int32" />
    </DeleteParameters>
</asp:ObjectDataSource>

Como en los ejemplos anteriores que no usaban la simultaneidad optimista, dedique un momento a borrar la propiedad ObjectDataSource s OldValuesParameterFormatString .

Puesto que se ha enlazado a un control ObjectDataSource que solo admite la eliminación, FormView s ItemTemplate solo ofrece el botón Eliminar, sin los botones Nuevo y Actualizar. Sin embargo, el marcado declarativo de FormView incluye un superfluo EditItemTemplate y InsertItemTemplate, que se puede quitar. Personalice el ItemTemplate para que solo muestre un subconjunto de los campos de datos del producto. He configurado la mía para mostrar el nombre del producto en un <h3> encabezado encima de sus nombres de proveedor y categoría (junto con el botón Eliminar).

<asp:FormView ID="FormView1" AllowPaging="True" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" runat="server">
    <ItemTemplate>
        <h3><i><%# Eval("ProductName") %></i></h3>
        <b>Category:</b>
        <asp:Label ID="CategoryNameLabel" runat="server"
            Text='<%# Eval("CategoryName") %>'>
        </asp:Label><br />
        <b>Supplier:</b>
        <asp:Label ID="SupplierNameLabel" runat="server"
            Text='<%# Eval("SupplierName") %>'>
        </asp:Label><br />
        <asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False"
            CommandName="Delete" Text="Delete">
        </asp:LinkButton>
    </ItemTemplate>
</asp:FormView>

Con estos cambios, tenemos una página web totalmente funcional que permite al usuario alternar los productos de uno en uno, con la capacidad de eliminar un producto simplemente haciendo clic en el botón Eliminar. En la figura 2 se muestra una captura de pantalla del progreso hasta ahora cuando se ve a través de un explorador.

FormView muestra información sobre un único producto

Figura 2: FormView muestra información sobre un único producto (haga clic para ver la imagen de tamaño completo)

Paso 2: Llamar a la función confirm(string) desde el evento onclick de los botones de eliminar Client-Side

Con formView creado, el paso final es configurar el botón Eliminar de forma que, cuando el visitante haga clic en él, se invoca la función de JavaScript confirm(string) . La adición de scripts del lado cliente a los eventos del lado cliente de Button, LinkButton o ImageButton onclick se puede realizar utilizando OnClientClick property, que es nuevo en ASP.NET 2.0. Puesto que queremos tener el valor de la confirm(string) función devuelta, simplemente establezca esta propiedad en: return confirm('Are you certain that you want to delete this product?');

Después de este cambio, la sintaxis declarativa de Delete LinkButton debe tener un aspecto similar al siguiente:

<asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False"
    CommandName="Delete" Text="Delete"
    OnClientClick="return confirm('Are you certain you want to delete this product?');">
</asp:LinkButton>

¡Eso es todo! En la figura 3 se muestra una captura de pantalla de esta confirmación en acción. Al hacer clic en el botón Eliminar se abre el cuadro de diálogo Confirmar. Si el usuario hace clic en Cancelar, el postback se cancela y el producto no se elimina. Sin embargo, si el usuario hace clic en Aceptar, la devolución de datos continúa y se invoca el método Delete() de ObjectDataSource, culminando en la eliminación del registro de la base de datos.

Nota:

La cadena que se pasa a la confirm(string) función de JavaScript se delimita con apóstrofos (en lugar de comillas). En JavaScript, las cadenas se pueden delimitar mediante cualquiera de los caracteres. Usamos apóstrofos aquí para que los delimitadores de la cadena pasada a confirm(string) no introduzcan ambigüedad con los delimitadores usados para el valor de la propiedad OnClientClick.

Ahora se muestra una confirmación al hacer clic en el botón Eliminar

Figura 3: Ahora se muestra una confirmación al hacer clic en el botón Eliminar (hacer clic para ver la imagen de tamaño completo)

Paso 3: Configurar la propiedad OnClientClick para el botón Eliminar en un commandField

Cuando se trabaja con un Button, LinkButton o ImageButton directamente en una plantilla, se puede asociar un cuadro de diálogo de confirmación simplemente configurando su OnClientClick propiedad para devolver los resultados de la función de JavaScript confirm(string) . Sin embargo, CommandField, que agrega un campo de botones Delete a un GridView o DetailsView, no tiene una OnClientClick propiedad que se pueda establecer mediante declaración. En su lugar, debemos hacer referencia mediante programación al botón Eliminar en el controlador de eventos adecuado DataBound de GridView o DetailsView y, a continuación, establecer su OnClientClick propiedad allí.

Nota:

Al establecer la propiedad del botón Eliminar dentro del controlador de eventos adecuado, tenemos acceso a los datos que estaban vinculados al registro actual. Esto significa que podemos ampliar el mensaje de confirmación para incluir detalles sobre el registro en particular, por ejemplo, "¿Está seguro de que desea eliminar el producto Chai?" Esta personalización también es posible en plantillas mediante la sintaxis de enlace de datos.

Para practicar la configuración de la OnClientClick propiedad para los botones Eliminar en un CommandField, vamos a añadir un elemento GridView en la página. Configure esta clase GridView para usar el mismo control ObjectDataSource que usa FormView. Limite también los BoundFields de GridView para incluir solo el nombre, la categoría y el proveedor del producto. Por último, marque la casilla para habilitar la opción Eliminar en el menú contextual inteligente de GridView. Esto agregará un CommandField a la colección del GridView Columns con su propiedad ShowDeleteButton establecida a true.

Después de realizar estos cambios, el marcado declarativo de GridView debe ser similar al siguiente:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" />
        <asp:BoundField DataField="ProductName" HeaderText="Product"
            SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" ReadOnly="True"
            SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName" HeaderText="Supplier" ReadOnly="True"
            SortExpression="SupplierName" />
    </Columns>
</asp:GridView>

CommandField contiene una única instancia de Delete LinkButton a la que se puede acceder mediante programación desde el controlador de eventos de RowDataBound GridView. Una vez al que se hace referencia, podemos establecer su OnClientClick propiedad en consecuencia. Cree un controlador de eventos para el RowDataBound evento mediante el código siguiente:

Protected Sub GridView1_RowDataBound(ByVal sender As Object, _
    ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) _
    Handles GridView1.RowDataBound

    If e.Row.RowType = DataControlRowType.DataRow Then
        ' reference the Delete LinkButton
        Dim db As LinkButton = CType(e.Row.Cells(0).Controls(0), LinkButton)

        ' Get information about the product bound to the row
        Dim product As Northwind.ProductsRow = _
            CType(CType(e.Row.DataItem, System.Data.DataRowView).Row, _
            Northwind.ProductsRow)

        db.OnClientClick = String.Format( _
            "return confirm('Are you certain you want to delete the {0} product?');", _
            product.ProductName.Replace("'", "\'"))
    End If
End Sub

Este controlador de eventos funciona con filas de datos (aquellas que tendrán el botón Eliminar) y comienza haciendo referencia mediante programación al botón Eliminar. En general, use el siguiente patrón:

Dim obj As ButtonType = _
    CType(e.Row.Cells(commandFieldIndex).Controls(controlIndex), ButtonType)

ButtonType es el tipo de botón que usa CommandField - Button, LinkButton o ImageButton. De forma predeterminada, CommandField usa LinkButtons, pero esto se puede personalizar a través de CommandField s ButtonType property. CommandFieldIndex es el índice ordinal del CommandField dentro de la colección GridView sColumns, mientras que controlIndex es el índice del botón Eliminar dentro de la colección CommandField.Controls El valor controlIndex depende de la posición del botón con respecto a otros botones del commandField. Por ejemplo, si el único botón mostrado en CommandField es el botón Eliminar, use un índice de 0. Sin embargo, si hay un botón Editar que precede al botón Eliminar, use un índice de 2. La razón por la que se usa un índice de 2 es porque el CommandField agrega dos controles antes del botón Eliminar: el botón Editar y un LiteralControl que se usa para agregar espacio entre los botones Editar y Eliminar.

En nuestro ejemplo concreto, CommandField usa LinkButtons y, siendo el campo más izquierdo, tiene un commandFieldIndex de 0. Puesto que no hay otros botones, sino el botón Eliminar en CommandField, usamos un controlIndex de 0.

Después de hacer referencia al botón Eliminar en CommandField, a continuación se obtiene información sobre el producto enlazado a la fila GridView actual. Por último, establecemos la propiedad del OnClientClick botón Eliminar en el JavaScript adecuado, que incluye el nombre del producto. Dado que la cadena de JavaScript que se pasa a la confirm(string) función se delimita mediante apóstrofos, debemos escapar de los apóstrofos que aparecen dentro del nombre del producto. En concreto, los apóstrofos del nombre del producto se escapan con "\'".

Una vez completados estos cambios, al hacer clic en un botón Eliminar de GridView se muestra un cuadro de diálogo de confirmación personalizado (vea la figura 4). Al igual que con el cuadro de mensaje de confirmación de FormView, si el usuario hace clic en Cancelar la devolución se cancela, lo que impide que se produzca la eliminación.

Nota:

Esta técnica también se puede usar para tener acceso mediante programación al botón Eliminar en commandField en un DetailsView. Sin embargo, para DetailsView, se crea un controlador de eventos para el DataBound evento, ya que DetailsView no tiene un RowDataBound evento.

Al hacer clic en el botón Eliminar de GridView, se muestra un cuadro de diálogo de confirmación personalizado

Figura 4: Hacer clic en el botón Eliminar de GridView muestra un cuadro de diálogo de confirmación personalizada (haga clic para ver la imagen de tamaño completo)

Uso de TemplateFields

Una de las desventajas de CommandField es que se debe tener acceso a sus botones a través de la indexación y que el objeto resultante debe convertirse al tipo de botón adecuado (Button, LinkButton o ImageButton). El uso de "números mágicos" y tipos codificados de forma rígida invita a problemas que no se pueden detectar hasta el tiempo de ejecución. Por ejemplo, si usted, u otro desarrollador, agrega botones nuevos al CommandField en algún momento en el futuro (por ejemplo, un botón Editar) o cambia la ButtonType propiedad , el código existente seguirá compilando sin error, pero visitar la página puede provocar una excepción o un comportamiento inesperado, dependiendo de cómo se escribió el código y de qué cambios se realizaron.

Un enfoque alternativo consiste en convertir GridView y DetailsView s CommandFields en TemplateFields. Esto generará un TemplateField con un ItemTemplate que contiene un LinkButton (o Button o ImageButton) para cada botón del CommandField. Estas propiedades de botones se pueden asignar mediante declaración, como vimos OnClientClick con FormView, o se puede acceder mediante programación en el controlador de eventos adecuado DataBound mediante el siguiente patrón:

Dim obj As ButtonType = CType(e.Row.FindControl("controlID"), ButtonType)

Donde controlID es el valor de la propiedad del botón s ID . Aunque este patrón todavía requiere un tipo codificado de forma rígida para la conversión, elimina la necesidad de indexación, lo que permite que el diseño cambie sin provocar un error en tiempo de ejecución.

Resumen

La función de JavaScript confirm(string) es una técnica que se usa habitualmente para controlar el flujo de trabajo de envío de formularios. Cuando se ejecuta, la función muestra un cuadro de diálogo modal y del lado cliente que incluye dos botones, Aceptar y Cancelar. Si el usuario hace clic en Aceptar, la confirm(string) función devuelve true; al hacer clic en Cancelar se devuelve false. Esta funcionalidad, junto con un comportamiento del explorador para cancelar un envío de formulario si un controlador de eventos durante el proceso de envío devuelve false, se puede usar para mostrar un cuadro de mensaje de confirmación al eliminar un registro.

La función confirm(string) se puede asociar a un controlador de eventos del lado cliente onclick del control Web Botón a través de la propiedad OnClientClick del control. Al trabajar con un botón Eliminar en una plantilla, ya sea en una de las plantillas de FormView o en un TemplateField en DetailsView o GridView, esta propiedad se puede establecer mediante declaración o mediante programación, como se ha visto en este tutorial.

¡Feliz programación!

Acerca del autor

Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 en 24 horas. Se puede contactar con él en mitchell@4GuysFromRolla.com.