WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

Validator の結果で背景を変更

by WebSurfer 18. July 2011 21:49

RequiredFieldValidator や RegularExpressionValidator の検証結果が無効の場合、対象の TextBox の BackgroundColor を赤などの目立つ色にしてユーザーの注意をひくというサンプルです。

検証結果が無効の場合、対象 TextBox の背景を赤に変更

ヒントは Change Background Color of Invalid Controls (ASP.NET Validator) というページに紹介されていたコードですが、これは TextBox に対し、Validator が一つだけならうまくいきますが、二つあるとうまくいきません。

例えば RequiredFieldValidator と RegularExpressionValidator を組み合わせて使った場合、何も入力しない場合は後者の isvalid は true になって ctrl.style.backgroundColor ="" で上書きされてしまい、TextBox の背景は赤くなりません。

以下に、その問題に対処したサンプルをアップしておきます。

ただし、自分は JavaScript 使いでも jQuery 使いでもないので(と言って、C# 使いでもないですが(汗))、スクリプトの書き方が変かもしれません。でも、一応期待通りに動くことは検証しました。

以下のコードは、実際に動かして試せるよう 実験室 にアップしましたので、興味のある方は試してみてください。この記事の下の方の「2011/7/20 追記」に書いた ErrorMessage と同期を取るためのコードは追加済みです。

<%@ 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 Page_Load(object sender, EventArgs e)
  {
    String csname = "OnSubmitScript";
    Type cstype = this.GetType();
    ClientScriptManager cs = Page.ClientScript;
    if (!cs.IsOnSubmitStatementRegistered(cstype, csname))
    {
      String cstext = "ChangeBackgroundColor();";
      cs.RegisterOnSubmitStatement(cstype, csname, cstext);
    }
  }

  protected void CustomValidator1_ServerValidate(
    object source, ServerValidateEventArgs args)
  {        
    string membership = args.Value.ToLower();

    if (membership == "gold" || membership == "silver")
    {
      args.IsValid = true;
    }
    else
    {
      args.IsValid = false;
    }      
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
  <script type="text/javascript">
  //<![CDATA[
    function CustomValidator1_ClientValidate(sender, args) {
      var membership = args.Value.toLowerCase();
      if (membership === "gold" || membership === "silver") {
        args.IsValid = true;
      } else {
        args.IsValid = false;
      }
    }

    function ChangeBackgroundColor() {
      var color = "#FFAAAA"

      var valid =
        $(Page_Validators).
        filter(function () { return this.isvalid == true; });

      var invalid =
        $(Page_Validators).
        filter(function () { return this.isvalid == false; });

      valid.each(function () {
        $("#" + $(this).get()[0].controltovalidate).
        css("backgroundColor", "");
      });

      invalid.each(function () {
        $("#" + $(this).get()[0].controltovalidate).
        css("backgroundColor", color);
      });
    }
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <table>
    <tr>
      <td>
        User Name
      </td>
      <td>
        <asp:TextBox ID="username" runat="server">
        </asp:TextBox>
      </td>
      <td>
        <asp:RequiredFieldValidator 
          ID="RequiredFieldValidator1" 
          runat="server" 
          ErrorMessage="ユーザー名は必須入力です。" 
          ControlToValidate="username" 
          ForeColor="Red" 
          Display="Dynamic">
        </asp:RequiredFieldValidator>
        <asp:RegularExpressionValidator 
          ID="RegularExpressionValidator1" 
          runat="server" 
          ErrorMessage=
            "半角アルファベットで 40 文字以内にしてください。" 
          ControlToValidate="username" 
          ForeColor="Red" 
          ValidationExpression="^[a-zA-Z''-'\s]{1,40}$" 
          Display="Dynamic">
        </asp:RegularExpressionValidator>
      </td>
    </tr>
    <tr>
      <td>
        Email
      </td>
      <td>
        <asp:TextBox ID="email" runat="server">
        </asp:TextBox>
      </td>
      <td>
        <asp:RequiredFieldValidator 
          ID="RequiredFieldValidator2" 
          runat="server" 
          ErrorMessage="メールアドレスは必須入力です。" 
          ControlToValidate="email" 
          ForeColor="Red" 
          Display="Dynamic">
        </asp:RequiredFieldValidator>
        <asp:RegularExpressionValidator 
          ID="RegularExpressionValidator2" 
          runat="server" 
          ErrorMessage=
            "メールアドレスの形式が正しくありません。" 
          ControlToValidate="email"
          ForeColor="Red" 
          ValidationExpression=
            "\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" 
          Display="Dynamic">
        </asp:RegularExpressionValidator>
      </td>
    </tr>
    <tr>
      <td>
        Membership
      </td>
      <td>
        <asp:TextBox ID="membership" runat="server">
        </asp:TextBox>
      </td>
      <td>
        <asp:RequiredFieldValidator 
          ID="RequiredFieldValidator3" 
          runat="server" 
          ErrorMessage="メンバーシップは必須入力です。" 
          ControlToValidate="membership" 
          ForeColor="Red" 
          Display="Dynamic">
        </asp:RequiredFieldValidator>
        <asp:CustomValidator 
          ID="CustomValidator1" 
          runat="server" 
          ErrorMessage=
            "Gold または Silver でなければなりません。" 
          ControlToValidate="membership"
          ForeColor="Red" 
          OnServerValidate=
            "CustomValidator1_ServerValidate" 
          Display="Dynamic" 
          ClientValidationFunction=
            "CustomValidator1_ClientValidate" >
        </asp:CustomValidator>
      </td>
    </tr>
  </table>
  <asp:Button ID="Button1" runat="server" Text="送信" />
  </form>
</body>
</html>

------------ 2011/7/20 追記 ------------

クライアント側での検証は、form が submit された時だけでなく、TextBox からフォーカスが外れた時も自動的にかかるようで、上記のコードでは ErrorMessage が消えても TextBox の背景は赤いままになってしまいます。

Validator の ErrorMessage と TextBox の背景の同期を取るには、TextBox の onblur 属性にも ChangeBackgroundColor() を設定します。Page_Load ハンドラで以下のようなコードを追加してやるとうまくいきます。

username.Attributes.Add("onblur", 
    "javascript:ChangeBackgroundColor()");
email.Attributes.Add("onblur", 
    "javascript:ChangeBackgroundColor()");
membership.Attributes.Add("onblur", 
    "javascript:ChangeBackgroundColor()");

------------ 2011/7/21 追記 ------------

IE の場合、フォーカスを外しても自動的に検証がかからないケースがあります。Firefox と Chrome でも試しましたが、こちらは期待通り検証がかかります。

具体的には以下のようなケースです。

最初に、空白または無効な文字列を TextBox に入力し、Tab キーでフォーカスを外すとクライアント側で検証がかかって ErrorMessage が表示され、onblur イベントが発生して ChangeBackgroundColor() メソッドが働き TextBox の背景色が赤になります。

次に、再度その TextBox に入力する際、オートコンプリートの一覧からマウスもしくはキー操作で文字列を選んで TextBox に表示し、その状態から Tab キーでフォーカスを外すと、今度は検証はかかりません。従い、有効な文字列なのにエラーとなったままになります。onblur イベントは発生して ChangeBackgroundColor() メソッドが働きますが、検証がかかってないので(即ち、検証結果が NG のままなので)TextBox の背景色は赤のままとなります。

ちなみに、オートコンプリートは一切使わず、有効な文字列を手打ちで TextBox に入力した場合は、フォーカスを外すと期待通り検証がかかります。従い、ErrorMessage は消えて TextBox の背景色も元に戻ります。

動作としては気に入らないですが、どうも IE のバグ仕様(?)らしいということで未対応です。

後で調べて分かったことですが、MSDN ライブラリの Walkthrough: Validating User Input in a Web Forms Page の Note に以下の文がありました。

"If you are using the auto-complete option in Internet Explorer, selecting a value from the auto-complete list will fill a value into the text box, but the client-side validator will not run."

Tags:

Validation

ValidationSummary の表示

by WebSurfer 8. September 2010 12:27

TextBox への入力を RequiredFieldValidator, RegularExpressionValidator でチェックし、エラーメッセージを ValidationSummary で表示するようにしたとします。以下のような感じです。

SummartValidator の表示

上の画面を表示したコードは以下のようになります。

<asp:TextBox ID="TextBox1" runat="server" />  
<asp:RequiredFieldValidator 
  ID="RequiredFieldValidator1"    
  runat="server" 
  ErrorMessage="入力必須" 
  ControlToValidate="TextBox1" 
  Text="*" 
  ForeColor="Red" />
<asp:RegularExpressionValidator 
  ID="RegularExpressionValidator1" 
  runat="server" 
  ErrorMessage="正しい郵便番号が必要" 
  ControlToValidate="TextBox1" 
  ValidationExpression="\d{3}(-(\d{4}|\d{2}))?" 
  Text="*" 
  ForeColor="Red" />
<br />
<asp:Button ID="Button1" 
  runat="server" 
  Text="実行" />  
<asp:ValidationSummary ID="ValidationSummary1" 
  runat="server" 
  ShowMessageBox="True" 
  ShowSummary="False" />    

TextBox にフォーカスがあるとき Enter キーを押すと form が submit(ポストバック)されますが、この時に入力が不正だった場合、期待した動作をするでしょうか?

ちなみに、期待した動作とは以下のとおりです。

  1. ポストバックがキャンセルされる。
  2. TextBox1 の横に「*」が表示される。
  3. エラーメッセージが ValidationSummary に表示される。

上記のコードで試してみると、1, 2 は実行されますが、3 は実行されないという結果になりました。IE8, Firefox 3.6.8, Opera 10.61 で同じ結果でした。

なお、Button1 をクリック(もしくは Button1 にフォーカスを当てて Enter キーを押す)した場合は、上記 1. 2, 3 すべて実行されます。それが、上の画像です。

TextBox にフォーカス → Enter キーでは、自動生成される検証用の JavaScript の一部のコードがスキップされることが原因です。何故スキップされるのか理由は分かりませんが。

対応策としては、ハック的なのでお勧めはできませんが、以下のようにすると、TextBox にフォーカス → Enter キーでも ValidationSummary が表示されるようになります。

protected void Page_Load(object sender, EventArgs e)
{
  TextBox1.Attributes.Add("onkeydown", 
    "if (event.keyCode == 13) Page_ClientValidate();");
}

Page_ClientValidate メソッドは引数に validationGroup を取りますが、上記のように空にしておいても正しく処置してくれるようです(IsValidationGroupMatch は true 返すので)。

TextBox にフォーカス → Enter キーで ValidationSummary が表示されないようになっているのには何か理由があって、無理に上記のようなことをすると予期せぬ副作用が出るのかもしれませんので、注意してください。

---------- 2011/4/30 追記 ----------

やっぱり予期せぬ副作用がありました。(汗)

まず、検証対象の TextBox が複数ある場合、onkeydown 属性に上記のような小細工をすると ValidationSummary がダブって出てしまい、期待した動きになりません。例えば、以下のコードで、一方の TextBox の入力が正しくて、他方が NG のとき、正しい方の TextBox にフォーカスを当てて Enter キーを押すと不具合が出ます。

もうひとつの問題は、オートコンプリート機能を利用する際、ドロップダウンリストに表示される選択肢を Enter キーで確定できなくなることです。

実際に試せるように 実験室 にアプリケーションをアップしておきましたので、興味のある方は試してみてください。

<%@ 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 Page_Load(object sender, EventArgs e)
  {
    TextBox1.Attributes.Add("onkeydown", 
      "if (event.keyCode == 13) Page_ClientValidate();");
    TextBox2.Attributes.Add("onkeydown",
      "if (event.keyCode == 13) Page_ClientValidate();");
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    郵便番号:
    <asp:TextBox id="TextBox1" runat="server" />  
    <asp:RequiredFieldValidator 
      ID="RequiredFieldValidator1"    
      runat="server" 
      ErrorMessage="入力必須" 
      ControlToValidate="TextBox1" 
      Text="*" 
      ForeColor="Red" 
      Display="Dynamic" />
    <asp:RegularExpressionValidator 
      ID="RegularExpressionValidator1" 
      runat="server" 
      ErrorMessage="正しい郵便番号が必要" 
      ControlToValidate="TextBox1" 
      ValidationExpression="\d{3}(-(\d{4}|\d{2}))?" 
      Text="*" 
      ForeColor="Red" 
      Display="Dynamic" />
    <br />
    メールアドレス:
    <asp:TextBox id="TextBox2" runat="server" />  
    <asp:RequiredFieldValidator 
      ID="RequiredFieldValidator2"    
      runat="server" 
      ErrorMessage="入力必須" 
      ControlToValidate="TextBox2" 
      Text="*" 
      ForeColor="Red" 
      Display="Dynamic" />
    <asp:RegularExpressionValidator 
      ID="RegularExpressionValidator2" 
      runat="server" 
      ErrorMessage="正しいメールアドレスが必要" 
      ControlToValidate="TextBox2" 
      ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" 
      Text="*" 
      ForeColor="Red" 
      Display="Dynamic" />
    <br />
    <asp:Button id="Button2" 
      runat="server" 
      Text="検証" />  
    <asp:ValidationSummary id="ValidationSummary1" 
      runat="server" 
      ShowMessageBox="True" 
      ShowSummary="False" 
      HeaderText="サマリーです" />
  </div>
  </form>
</body>
</html>

Tags:

Validation

About this blog

2010年5月にこのブログを立ち上げました。その後ブログ2を追加し、ここはプログラミング関係、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  December 2022  >>
MoTuWeThFrSaSu
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar