これまでに作成したインターフェイスでは、ユーザーが [編集] ボタンをクリックするときに [削除] ボタンをクリックして、誤ってデータを削除する可能性があります。 このチュートリアルでは、[削除] ボタンがクリックされたときに表示されるクライアント側の確認ダイアログ ボックスを追加します。
イントロダクション
過去のいくつかのチュートリアルでは、アプリケーション アーキテクチャ、ObjectDataSource、データ Web コントロールを組み合わせ、挿入、編集、削除の機能を提供する方法について説明しました。 これまでに調べた削除インターフェイスは、[削除] ボタンで構成されています。このボタンをクリックするとポストバックが発生し、ObjectDataSource の Delete()
メソッドが呼び出されます。 次に、 Delete()
メソッドは、ビジネス ロジック層から構成されたメソッドを呼び出します。これにより、呼び出しがデータ アクセス層に伝達され、実際の DELETE
ステートメントがデータベースに発行されます。
このユーザー インターフェイスを使用すると、閲覧者は GridView、DetailsView、または FormView コントロールを使用してレコードを削除することができますが、ユーザーが [削除] ボタンをクリックしても、何らかの確認は行いません。 ユーザーが [編集] をクリックしようとしたときに誤って [削除] ボタンをクリックした場合、更新する予定のレコードは削除されます。 これを防ぐために、このチュートリアルでは、[削除] ボタンがクリックされたときに表示されるクライアント側の確認ダイアログ ボックスを追加します。
JavaScript confirm(string)
関数は、文字列入力パラメーターを、OK と Cancel の 2 つのボタンが備わっているモーダル ダイアログ ボックス内のテキストとして表示します (図 1 を参照)。
confirm(string)
関数は、クリックされたボタンに応じてブール値を返します (ユーザーが [OK] をクリックした場合はtrue
し、[キャンセル] をクリックした場合はfalse
)。
図 1: JavaScript confirm(string)
メソッドがモーダルメッセージ ボックス Client-Side 表示する
フォームの送信中に、クライアント側のイベント ハンドラーから false
の値が返された場合、フォームの送信は取り消されます。 この機能を使用して、[削除] ボタンのクライアント側 onclick
イベント ハンドラーに、 confirm("Are you sure you want to delete this product?")
への呼び出しの値を返すことができます。 ユーザーが [キャンセル] をクリックすると、 confirm(string)
は false を返し、フォームの送信が取り消されます。 ポストバックがないと、[削除] ボタンがクリックされた製品は削除されません。 ただし、ユーザーが確認ダイアログ ボックスで [OK] をクリックした場合、ポストバックは変更されないまま続行され、製品は削除されます。 この手法の詳細については、 JavaScript の confirm()
メソッドを使用してフォームの送信を制御 する方法に関するページを参照してください。
必要なクライアント側スクリプトの追加は、テンプレートを使用する場合と CommandField を使用する場合とは若干異なります。 したがって、このチュートリアルでは、FormView と GridView の両方の例を見ていきます。
注
このチュートリアルで説明したように、クライアント側の確認手法を使用すると、ユーザーは JavaScript をサポートするブラウザーにアクセスしており、JavaScript が有効になっていることを前提としています。 これらの前提条件のいずれかが特定のユーザーに当てはまらない場合、[削除] ボタンをクリックすると、すぐにポストバックが発生します (確認メッセージ ボックスは表示されません)。
手順 1: 削除をサポートする FormView の作成
まず、ConfirmationOnDelete.aspx
フォルダー内のEditInsertDelete
ページに FormView を追加し、ProductsBLL
クラスの GetProducts()
メソッドを使用して製品情報を取得する新しい ObjectDataSource にバインドします。 また、 ProductsBLL
クラスの DeleteProduct(productID)
メソッドが ObjectDataSource の Delete()
メソッドにマップされるように ObjectDataSource を構成します。INSERT タブと UPDATE タブのドロップダウン リストが (None) に設定されていることを確認します。 最後に、FormView のスマート タグの [ページングを有効にする] チェック ボックスをオンにします。
これらの手順の後、新しい ObjectDataSource の宣言型マークアップは次のようになります。
<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>
オプティミスティック コンカレンシーを使用しなかった過去の例と同様に、ObjectDataSource の OldValuesParameterFormatString
プロパティをクリアします。
削除のみをサポートする ObjectDataSource コントロールにバインドされているため、FormView ItemTemplate
では [削除] ボタンのみが提供され、[新規作成] ボタンと [更新] ボタンがありません。 ただし、FormView の宣言型マークアップには、余分な EditItemTemplate
と InsertItemTemplate
が含まれています。これは削除できます。 製品データ フィールドのサブセットのみが表示されるように、 ItemTemplate
をカスタマイズします。 サプライヤー名とカテゴリ名の上にある <h3>
見出しに製品名を表示するように mine を構成しました ([削除] ボタンと共に)。
<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>
これらの変更により、ユーザーが一度に 1 つずつ製品を切り替え、単に [削除] ボタンをクリックするだけで製品を削除できる、完全に機能する Web ページが用意されています。 図 2 は、ブラウザーから見たときのこれまでの進行状況のスクリーン ショットを示しています。
図 2: FormView は、1 つの製品に関する情報を示しています (フルサイズの画像を表示する をクリックします)
手順 2: delete Buttons Client-Side onclick イベントから confirm(string) 関数を呼び出す
FormView を作成したら、最後の手順は、ビジターがクリックしたときに JavaScript confirm(string)
関数が呼び出されるように [削除] ボタンを構成することです。 Button、LinkButton、または ImageButton のクライアント側 onclick
イベントへのクライアント側スクリプトの追加は、ASP.NET 2.0 の新機能である OnClientClick property
を使用することで実現できます。
confirm(string)
関数の値を返す必要があるため、このプロパティを次に設定するだけです。return confirm('Are you certain that you want to delete this product?');
この変更後、Delete LinkButton の宣言構文は次のようになります。
<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>
それがすべてです! 図 3 に、この確認の動作を示すスクリーン ショットを示します。 [削除] ボタンをクリックすると、[確認] ダイアログ ボックスが表示されます。 ユーザーが [キャンセル] をクリックした場合、ポストバックは取り消され、製品は削除されません。 ただし、ユーザーが [OK] をクリックした場合、ポストバックが続行され、ObjectDataSource の Delete()
メソッドが呼び出され、削除されるデータベース レコードに結び付けられます。
注
confirm(string)
JavaScript 関数に渡される文字列は、(引用符ではなく) アポストロフィで区切られます。 JavaScript では、文字列はいずれかの文字を使用して区切ることができます。 ここではアポストロフィを使用して、 confirm(string)
に渡される文字列の区切り記号が、 OnClientClick
プロパティ値に使用される区切り記号にあいまいさを持たないようにします。
図 3: 削除ボタンをクリックすると確認が表示されるようになりました (フルサイズの画像を表示する] をクリックします)。
手順 3: CommandField の [削除] ボタンの OnClientClick プロパティを構成する
テンプレートで Button、LinkButton、または ImageButton を直接操作する場合は、JavaScript OnClientClick
関数の結果を返すように confirm(string)
プロパティを構成するだけで、確認ダイアログ ボックスを関連付けることができます。 ただし、GridView または DetailsView に [削除] ボタンのフィールドを追加する CommandField には、宣言によって設定できる OnClientClick
プロパティはありません。 代わりに、プログラムで GridView または DetailsView の適切な DataBound
イベント ハンドラーの [削除] ボタンを参照し、その OnClientClick
プロパティを設定する必要があります。
注
適切なOnClientClick
イベント ハンドラーで Delete ボタンの DataBound
プロパティを設定すると、現在のレコードにバインドされたデータにアクセスできます。 これにより、確認メッセージを拡張して特定のレコードに関する詳細を含めることができます。例えば、「Chai製品を削除してもよろしいですか?」といった内容を追加することができます。このようなカスタマイズは、データバインドの構文を使用するテンプレートでも可能です。
CommandField の [削除] ボタンの OnClientClick
プロパティの設定を練習するには、ページに GridView を追加します。 FormView で使用されるのと同じ ObjectDataSource コントロールを使用するように、この GridView を構成します。 また、GridView の BoundFields には、製品名、カテゴリ、およびサプライヤーのみを含むように制限します。 最後に、GridView のスマート タグから [削除を有効にする] チェック ボックスをオンにします。 これにより、Columns
プロパティが ShowDeleteButton
に設定された状態で、GridView の true
コレクションに CommandField が追加されます。
これらの変更を行った後、GridView の宣言型マークアップは次のようになります。
<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 には、GridView の RowDataBound
イベント ハンドラーからプログラムでアクセスできる単一の Delete LinkButton インスタンスが含まれています。 参照されたら、それに応じてその OnClientClick
プロパティを設定できます。 次のコードを使用して、 RowDataBound
イベントのイベント ハンドラーを作成します。
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
このイベント ハンドラーはデータ行 ([削除] ボタンを持つ行) で動作し、まずプログラムで [削除] ボタンを参照します。 一般に、次のパターンを使用します。
Dim obj As ButtonType = _
CType(e.Row.Cells(commandFieldIndex).Controls(controlIndex), ButtonType)
ButtonType は、CommandField - Button、LinkButton、または ImageButton で使用されるボタンの種類です。 既定では、CommandField は LinkButtons を使用しますが、これは CommandField の ButtonType property
を使用してカスタマイズできます。
commandFieldIndex は GridView s Columns
コレクション内の CommandField の序数インデックスですが、controlIndex は CommandField の Controls
コレクション内の Delete ボタンのインデックスです。
controlIndex 値は、CommandField 内の他のボタンを基準としたボタンの位置によって異なります。 たとえば、CommandField に表示される唯一のボタンが [削除] ボタンの場合は、インデックス 0 を使用します。 ただし、[削除] ボタンの前に [編集] ボタンがある場合は、インデックス 2 を使用します。 2 のインデックスが使用される理由は、[削除] ボタンの前に CommandField によって 2 つのコントロールが追加されるためです。[編集] ボタンと 、[編集] ボタンと [削除] ボタンの間にスペースを追加するために使用される LiteralControl です。
この特定の例では、CommandField は LinkButtons を使用し、左端のフィールドの commandFieldIndex は 0 です。 CommandField の [削除] ボタン以外のボタンはないため、 controlIndex は 0 を使用します。
CommandField の [削除] ボタンを参照した後、次に現在の GridView 行にバインドされている製品に関する情報を取得します。 最後に、Delete ボタンの OnClientClick
プロパティを、製品名を含む適切な JavaScript に設定します。
confirm(string)
関数に渡される JavaScript 文字列はアポストロフィを使用して区切られます。したがって、製品名内に出現するアポストロフィはエスケープする必要があります。 特に、製品名に含まれるアポストロフィは、"\'
" でエスケープされます。
これらの変更が完了すると、GridView の [削除] ボタンをクリックすると、カスタマイズされた確認ダイアログ ボックスが表示されます (図 4 を参照)。 FormView の確認メッセージ ボックスと同様に、ユーザーが [キャンセル] をクリックするとポストバックが取り消され、削除が行われなくなります。
注
この手法を使用して、DetailsView の CommandField の [削除] ボタンにプログラムでアクセスすることもできます。 ただし、DetailsView にはDataBound
イベントがないため、DetailsView の場合は、RowDataBound
イベントのイベント ハンドラーを作成します。
図 4: GridView の [削除] ボタンをクリックすると、カスタマイズされた確認ダイアログ ボックスが表示されます (フルサイズの画像を表示する をクリックします)。
TemplateFields の使用
CommandField の欠点の 1 つは、インデックスを作成してボタンにアクセスし、結果のオブジェクトを適切なボタンの種類 (Button、LinkButton、または ImageButton) にキャストする必要があることです。 "マジックナンバー" とハードコーディングされた型を使用すると、実行時まで検出できない問題が発生します。 たとえば、ユーザーまたは別の開発者が、将来のどこかの時点で CommandField に新しいボタン (編集ボタンなど) を追加したり、 ButtonType
プロパティを変更したりした場合、既存のコードはエラーなしでコンパイルされますが、ページにアクセスすると、コードの記述方法や変更内容によっては、例外や予期しない動作が発生する可能性があります。
別の方法として、GridView と DetailsView の CommandFields を TemplateFields に変換します。 これにより、CommandField 内の各ボタンの LinkButton (または Button または ImageButton) を持つ ItemTemplate
を含む TemplateField が生成されます。 プロパティ OnClientClick
これらのボタンは、FormView で確認したように宣言によって割り当てることもできます。また、次のパターンを使用して、適切な DataBound
イベント ハンドラーでプログラムでアクセスすることもできます。
Dim obj As ButtonType = CType(e.Row.FindControl("controlID"), ButtonType)
controlID は、ボタンの ID
プロパティの値です。 このパターンではキャストにハードコーディングされた型が必要ですが、インデックス作成が不要になり、実行時エラーが発生することなくレイアウトを変更できます。
概要
JavaScript confirm(string)
関数は、フォーム送信ワークフローを制御するために一般的に使用される手法です。 この関数を実行すると、2 つのボタン [OK] と [キャンセル] を含む、クライアント側のモーダル ダイアログ ボックスが表示されます。 ユーザーが [OK] をクリックすると、 confirm(string)
関数は true
を返します。[キャンセル] をクリックすると、 false
が返されます。 この機能は、送信プロセス中にイベント ハンドラーが false
を返した場合にフォームの送信を取り消すブラウザーの動作と組み合わせて、レコードを削除するときに確認メッセージ ボックスを表示するために使用できます。
confirm(string)
関数は、コントロールの onclick
プロパティを使用して、Button Web コントロールのクライアント側OnClientClick
イベント ハンドラーに関連付けることができます。 FormView のテンプレートの 1 つ、または DetailsView または GridView の TemplateField でテンプレートの [削除] ボタンを使用する場合、このプロパティは、このチュートリアルで説明したように、宣言またはプログラムによって設定できます。
プログラミングに満足!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジを使用しています。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズ・ティーチ・セルフ ASP.NET 24時間で2.0です。 彼には mitchell@4GuysFromRolla.comで連絡できます。