ASP.NET の検証コントロール(RequiredFieldValidator, RegularExpressionValidator など)を使用して、Display プロパティを Dynamic に設定したときの注意点です。
この件は stackoverflow の記事 でも報告されています。ただ、実は自分はつい最近までこの問題は知らなかったです。(汗)
例えば、以下のように RequiredFieldValidator を配置して、その直後に Button を配置したとします。
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void Button1_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
// 何らかの処置。
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1"
runat="server"
ErrorMessage="エラーメッセージ"
ControlToValidate="TextBox1"
Display="Dynamic">
</asp:RequiredFieldValidator>
<asp:Button ID="Button1"
runat="server"
Text="Button"
OnClick="Button1_Click" />
</div>
</form>
</body>
</html>
上記のコードでは以下の手順で問題を再現できます。
-
TextBox は空のまま Button をクリックする。
-
クライアント側で検証がかかり、ErrorMessage プロパティに設定した「エラーメッセージ」が表示される。
-
TextBox に文字を入力して Button をクリックする。 ⇒ 「エラーメッセージ」は消えるがポストバックがかからない。
-
再度 Button をクリックする。 ⇒ ポストバックがか���る。
期待される動きは、上記 3 で「エラーメッセージ」が消えるとともにポストバックがかかるということのはずですが、そうはなりません。
上記のコードにおける解決策は、Button の直前に改行 ( <br /> ) を入れることです。そうしないとうまく行かない理由は以下の通りです。
Validator のエラーメッセージは html コードでは span 要素となり、JavaScript による検証結果により表示/非表示を切り替えています。
Display プロパティが Dynamic に設定されている場合は、当該 span 要素の style 属性を "display:none;" または "display:inline;" に設定することにより表示/非常時を切り替えます。
検証対象の TextBox にフォーカスを当ててからフォーカスを外す(例えば、TextBox に入力してから form を submit するために Button をクリックする)と、 そのタイミングで JavaScript による検証がかかるようになっています。
検証結果によって "display:inline;" が "display:none;" に(またはその逆に)書き換えられるので、エラーメッセージの部分のページレイアウトが変わることになります。
従って、上記のコードのように、RequiredFieldValidator の直後に Button が配置されているような場合、エラーメッセージが表示/非表示になる分だけ画面上でボタンが左右に移動します。
ボタンが移動すると、<input type="submit" ... /> タイプのボタンをクリックしたにもかかわらず form が submit されません。 即ち、ポストバックされないという期待に反する動作になります。
なお Button が動くのは左右でなくても、例えばエラーメッセージを p 要素に入れると上下に移動しますが、その場合でも同じくform は submit されません。
このことは、ASP.NET の検証コントロールを使った場合に限った話ではなく、html 要素と JavaScript だけでも再現できます。 以下のサンプルコードは、html 要素と JavaScript だけでこの問題(ボタンが動くと submit されない)を再現する例です。
サンプルコードを実際に動かして試すことができるよう 実験室 にアップしました。興味のある方は試してみてください。
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>WebSurfer's Page - 実験室</title>
<script src="/scripts/jquery-1.8.3.min.js" type="text/javascript">
</script>
<script type="text/javascript">
//<![CDATA[
function toggleDisplay() {
var validator = $('#RequiredFieldValidator1');
if (validator.css("display") == "none") {
validator.css("display", "inline");
} else {
validator.css("display", "none");
}
}
//]]>
</script>
</head>
<body>
<form id="form1" runat="server"
onsubmit="javascript:return confirm('Submit しますか?');">
<div>
<input name="textbox1" type="text" id="1extbox1"
onblur="javascript: toggleDisplay();" />
<span id="RequiredFieldValidator1"
style="display:none;">エラーメッセージ</span>
<input type="submit" name="button1" value="POST"
id="button1" />
</div>
</form>
</body>
</html>
ちなみに、Display プロパティが Static に設定されている場合は、style 属性を "visibility:hidden;" または "visibility:visible" に設定するので、 表示/非表示を切り替えてもページのレイアウトは変わりません。結果、ボタンは動かないのでこの問題は起こりません。