Adicionar confirmação do lado do cliente ao excluir (VB)
por Scott Mitchell
Nas interfaces que criamos até agora, um usuário pode excluir dados acidentalmente clicando no botão Excluir quando quiser clicar no botão Editar. Neste tutorial, adicionaremos uma caixa de diálogo de confirmação do lado do cliente que aparece quando o botão Excluir é clicado.
Introdução
Nos últimos tutoriais, vimos como usar nossa arquitetura de aplicativo, ObjectDataSource e os controles da Web de dados em conjunto para fornecer recursos de inserção, edição e exclusão. As interfaces de exclusão que examinamos até agora foram compostas por um botão Excluir que, quando clicado, causa um postback e invoca o método ObjectDataSource.Delete()
Em Delete()
seguida, o método invoca o método configurado da Camada de Lógica de Negócios, que propaga a chamada para a Camada de Acesso a Dados, emitindo a instrução real DELETE
para o banco de dados.
Embora essa interface do usuário permita que os visitantes excluam registros por meio dos controles GridView, DetailsView ou FormView, ela não tem qualquer tipo de confirmação quando o usuário clica no botão Excluir. Se um usuário clicar acidentalmente no botão Excluir quando quiser clicar em Editar, o registro que ele pretendia atualizar será excluído. Para ajudar a evitar isso, neste tutorial, adicionaremos uma caixa de diálogo de confirmação do lado do cliente que aparece quando o botão Excluir é clicado.
A função JavaScript confirm(string)
exibe seu parâmetro de entrada de cadeia de caracteres como o texto dentro de uma caixa de diálogo modal que vem equipada com dois botões – OK e Cancelar (consulte a Figura 1). A confirm(string)
função retorna um valor booliano dependendo de qual botão é clicado (true
, se o usuário clicar em OK e false
se clicar em Cancelar).
Figura 1: o método JavaScript confirm(string)
exibe uma caixa de mensagem modal Client-Side
Durante um envio de formulário, se um valor de false
for retornado de um manipulador de eventos do lado do cliente, o envio do formulário será cancelado. Usando esse recurso, podemos fazer com que o manipulador de eventos do lado onclick
do cliente do botão Excluir retorne o valor de uma chamada para confirm("Are you sure you want to delete this product?")
. Se o usuário clicar em Cancelar, confirm(string)
retornará false, fazendo com que o envio do formulário seja cancelado. Sem postback, o produto cujo botão Excluir foi clicado não será excluído. No entanto, se o usuário clicar em OK na caixa de diálogo de confirmação, o postback continuará inabalável e o produto será excluído. Consulte Usando o método javaScript para confirm()
controlar o envio de formulário para obter mais informações sobre essa técnica.
Adicionar o script do lado do cliente necessário difere ligeiramente se estiver usando modelos do que ao usar um CommandField. Portanto, neste tutorial, examinaremos um exemplo de FormView e GridView.
Observação
O uso de técnicas de confirmação do lado do cliente, como as discutidas neste tutorial, pressupõe que os usuários estejam visitando com navegadores que dão suporte a JavaScript e que tenham o JavaScript habilitado. Se qualquer uma dessas suposições não for verdadeira para um usuário específico, clicar no botão Excluir causará imediatamente um postback (não exibir uma caixa de mensagem de confirmação).
Etapa 1: Criando um FormView que dá suporte à exclusão
Comece adicionando um FormView à ConfirmationOnDelete.aspx
página na pasta , associando-o EditInsertDelete
a um novo ObjectDataSource que efetua pull das informações do produto por meio do ProductsBLL
método da classe s GetProducts()
. Configure também o ObjectDataSource para que o ProductsBLL
método da classe s DeleteProduct(productID)
seja mapeado para o método objectDataSource; Delete()
verifique se as listas suspensas das guias INSERT e UPDATE estão definidas como (Nenhum). Por fim, marcar caixa de seleção Habilitar Paginação na marca inteligente formView.
Após essas etapas, a nova marcação declarativa do ObjectDataSource será semelhante à seguinte:
<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 em nossos exemplos anteriores que não usavam simultaneidade otimista, reserve um momento para limpar a propriedade objectDataSource.OldValuesParameterFormatString
Como ele foi associado a um controle ObjectDataSource que dá suporte apenas à exclusão, o FormView s ItemTemplate
oferece apenas o botão Excluir, sem os botões Novo e Atualizar. No entanto, a marcação declarativa do FormView inclui um supérfluo e InsertItemTemplate
, que podem ser removidosEditItemTemplate
. Reserve um momento para personalizar o ItemTemplate
para que seja mostrado apenas um subconjunto dos campos de dados do produto. Configurei o meu para mostrar o nome do produto em um <h3>
título acima de seu fornecedor e nomes de categoria (juntamente com o botão Excluir).
<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>
Com essas alterações, temos uma página da Web totalmente funcional que permite que um usuário alterne os produtos um de cada vez, com a capacidade de excluir um produto simplesmente clicando no botão Excluir. A Figura 2 mostra uma captura de tela do nosso progresso até agora quando exibida por meio de um navegador.
Figura 2: O FormView mostra informações sobre um único produto (clique para exibir a imagem em tamanho real)
Etapa 2: Chamando a função confirm(string) do evento Delete Buttons Client-Side onclick
Com o FormView criado, a etapa final é configurar o botão Excluir de modo que, quando ele é clicado pelo visitante, a função JavaScript confirm(string)
é invocada. A adição de script do lado do cliente a um evento do lado onclick
do cliente Button, LinkButton ou ImageButton pode ser realizada por meio do uso do OnClientClick property
, que é novo no ASP.NET 2.0. Como queremos que o valor da confirm(string)
função seja retornado, basta definir essa propriedade como: return confirm('Are you certain that you want to delete this product?');
Após essa alteração, a sintaxe declarativa Excluir LinkButton deverá ser semelhante a:
<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>
Isso é tudo o que há para ele! A Figura 3 mostra uma captura de tela dessa confirmação em ação. Clicar no botão Excluir abre a caixa de diálogo confirmar. Se o usuário clicar em Cancelar, o postback será cancelado e o produto não será excluído. Se, no entanto, o usuário clicar em OK, o postback continuará e o método objectDataSource será Delete()
invocado, culminando na exclusão do registro de banco de dados.
Observação
A cadeia de caracteres passada para a confirm(string)
função JavaScript é delimitada com apóstrofos (em vez de aspas). No JavaScript, as cadeias de caracteres podem ser delimitadas usando qualquer um dos caracteres. Usamos apóstrofos aqui para que os delimitadores para a cadeia de caracteres passada confirm(string)
não introduzam uma ambiguidade com os delimitadores usados para o valor da OnClientClick
propriedade.
Figura 3: Uma confirmação agora é exibida ao clicar no botão Excluir (clique para exibir a imagem em tamanho real)
Etapa 3: Configurando a propriedade OnClientClick para o botão Excluir em um CommandField
Ao trabalhar com um Button, LinkButton ou ImageButton diretamente em um modelo, uma caixa de diálogo de confirmação pode ser associada a ela simplesmente configurando sua OnClientClick
propriedade para retornar os resultados da função JavaScript confirm(string)
. No entanto, o CommandField - que adiciona um campo de botões Excluir a um GridView ou DetailsView - não tem uma OnClientClick
propriedade que pode ser definida declarativamente. Em vez disso, devemos referenciar programaticamente o botão Excluir no manipulador de eventos apropriado DataBound
de GridView ou DetailsView e, em seguida, definir sua OnClientClick
propriedade lá.
Observação
Ao definir a propriedade do botão Excluir no OnClientClick
manipulador de eventos apropriado DataBound
, temos acesso aos dados associados ao registro atual. Isso significa que podemos estender a mensagem de confirmação para incluir detalhes sobre o registro específico, como" Tem certeza de que deseja excluir o produto Chai?" Essa personalização também é possível em modelos usando a sintaxe de associação de dados.
Para praticar a configuração da OnClientClick
propriedade para os botões Excluir em um CommandField, vamos adicionar um GridView à página. Configure este GridView para usar o mesmo controle ObjectDataSource que o FormView usa. Limite também os BoundFields do GridView para incluir apenas o nome, a categoria e o fornecedor do produto. Por fim, marcar a caixa de seleção Habilitar Exclusão da marca inteligente GridView. Isso adicionará um CommandField à coleção gridView com Columns
sua ShowDeleteButton
propriedade definida true
como .
Depois de fazer essas alterações, a marcação declarativa do GridView deve ser semelhante à seguinte:
<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>
O CommandField contém uma única instância delete LinkButton que pode ser acessada programaticamente no manipulador de eventos gridView.RowDataBound
Depois de referenciados, podemos definir sua OnClientClick
propriedade adequadamente. Crie um manipulador de eventos para o RowDataBound
evento usando o seguinte código:
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
Esse manipulador de eventos funciona com linhas de dados (aquelas que terão o botão Excluir) e começa referenciando programaticamente o botão Excluir. Em geral, use o seguinte padrão:
Dim obj As ButtonType = _
CType(e.Row.Cells(commandFieldIndex).Controls(controlIndex), ButtonType)
ButtonType é o tipo de botão que está sendo usado pelo CommandField - Button, LinkButton ou ImageButton. Por padrão, o CommandField usa LinkButtons, mas isso pode ser personalizado por meio do CommandField s ButtonType property
. O commandFieldIndex é o índice ordinal do CommandField dentro da coleção GridView, Columns
enquanto controlIndex é o índice do botão Delete dentro da coleção CommandField s Controls
. O valor controlIndex depende da posição do botão em relação a outros botões no CommandField. Por exemplo, se o único botão exibido no CommandField for o botão Excluir, use um índice de 0. Se, no entanto, houver um botão Editar que precede o botão Excluir, use um índice de 2. O motivo pelo qual um índice de 2 é usado é porque dois controles são adicionados pelo CommandField antes do botão Excluir: o botão Editar e um LiteralControl que é usado para adicionar algum espaço entre os botões Editar e Excluir.
Para nosso exemplo específico, o CommandField usa LinkButtons e, sendo o campo mais à esquerda, tem um commandFieldIndex de 0. Como não há outros botões além do botão Excluir no CommandField, usamos um controlIndex de 0.
Depois de referenciar o botão Excluir no CommandField, em seguida, obteremos informações sobre o produto associado à linha GridView atual. Por fim, definimos a propriedade do botão Excluir como OnClientClick
o JavaScript apropriado, que inclui o nome do produto. Como a cadeia de caracteres JavaScript passada para a confirm(string)
função é delimitada usando apóstrofos, devemos escapar de todos os apóstrofos que aparecem dentro do nome do produto. Em particular, todos os apóstrofos no nome do produto são escapados com "\'
".
Com essas alterações concluídas, clicar em um botão Excluir no GridView exibe uma caixa de diálogo de confirmação personalizada (consulte a Figura 4). Assim como acontece com a caixa de mensagem de confirmação do FormView, se o usuário clicar em Cancelar, o postback será cancelado, impedindo assim que a exclusão ocorra.
Observação
Essa técnica também pode ser usada para acessar programaticamente o botão Excluir no CommandField em um DetailsView. No entanto, para o DetailsView, você criaria um manipulador de eventos para o DataBound
evento, pois o DetailsView não tem um RowDataBound
evento.
Figura 4: Clicar no botão Excluir do GridView exibe uma caixa de diálogo de confirmação personalizada (clique para exibir a imagem em tamanho real)
Usando TemplateFields
Uma das desvantagens do CommandField é que seus botões devem ser acessados por meio da indexação e que o objeto resultante deve ser convertido no tipo de botão apropriado (Button, LinkButton ou ImageButton). O uso de "números mágicos" e tipos embutidos em código convida problemas que não podem ser descobertos até o runtime. Por exemplo, se você ou outro desenvolvedor adicionar novos botões ao CommandField em algum momento no futuro (como um botão Editar) ou alterar a ButtonType
propriedade, o código existente ainda será compilado sem erros, mas visitar a página pode causar uma exceção ou um comportamento inesperado, dependendo de como o código foi escrito e quais alterações foram feitas.
Uma abordagem alternativa é converter os CommandFields de GridView e DetailsView em TemplateFields. Isso gerará um TemplateField com um ItemTemplate
que tem um LinkButton (ou Button ou ImageButton) para cada botão no CommandField. Essas propriedades de botões podem ser atribuídas OnClientClick
declarativamente, como vimos com o FormView, ou podem ser acessadas programaticamente no manipulador de eventos apropriado DataBound
usando o seguinte padrão:
Dim obj As ButtonType = CType(e.Row.FindControl("controlID"), ButtonType)
Em que controlID é o valor da propriedade s do ID
botão. Embora esse padrão ainda exija um tipo embutido em código para a conversão, ele remove a necessidade de indexação, permitindo que o layout seja alterado sem resultar em um erro de runtime.
Resumo
A função JavaScript confirm(string)
é uma técnica comumente usada para controlar o fluxo de trabalho de envio de formulário. Quando executada, a função exibe uma caixa de diálogo modal do lado do cliente que inclui dois botões, OK e Cancelar. Se o usuário clicar em OK, a confirm(string)
função retornará true
; clicar em Cancelar retornará false
. Essa funcionalidade, juntamente com o comportamento de um navegador para cancelar um envio de formulário se um manipulador de eventos durante o processo de envio retornar false
, poderá ser usada para exibir uma caixa de mensagens de confirmação ao excluir um registro.
A confirm(string)
função pode ser associada a um manipulador de eventos do lado onclick
do cliente do controle Web de botão por meio da propriedade s do OnClientClick
controle. Ao trabalhar com um botão Excluir em um modelo - em um dos modelos do FormView ou em um TemplateField no DetailsView ou GridView - essa propriedade pode ser definida de forma declarativa ou programática, como vimos neste tutorial.
Programação feliz!
Sobre o autor
Scott Mitchell, autor de sete livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Ele pode ser contatado em mitchell@4GuysFromRolla.com. ou através de seu blog, que pode ser encontrado em http://ScottOnWriting.NET.