WebSurfer's Home

Filter by APML

リストコントロール上の選択結果を取得

by WebSurfer 9. November 2012 00:28

注意:
DOM Level 3 Events がサポートされていない IE8 以前に対応するには、下の「2013/2/7 追加」に書いた対応が必要です。

ASP.NET のリストコントロール DropDownList, ListBox, RadioButtonList, CheckBoxList において、ユーザーが選択した ListItem に設定された Value プロパティや Text プロパティの値を、クライアント側で取得する方法です。

ListItem の Text プロパティの値

クライアント側で取得するので、ASP.NET がサーバーコントロールから生成した html コードがどのようになっているかを把握する必要があります。

DropDownList と ListBox からレンダリングされる html コードは、select 要素と option 要素で構成されます。ListItem の Value と Text は option 要素の value 属性と内部 HTML として設定されます。

RadioButtonList と CheckBoxList からレンダリングされる html コードは、input 要素と label 要素で構成されます。ListItem の Value は input 要素の value 属性として、Text は label 要素の内部 HTML として設定されます。(2012/11/10 追記: .NET 3.5 の CheckBoxList には問題があります。下の注記参照)

DropDownList, ListBox, RadioButtonList, CheckBoxList から生成された html コードの詳細は 実験室 のページのソースを見てください。下に提示したサンプルを実際に動かして試せるようしてあります。

クライアントスクリプトは JavaScript を使用することになりますが、JavaScript だけでは自分には難しいので、jQuery のセレクタの助けを借ります。

JavaScript + jQuery のサンプルコードは JQUERY API のページにもあります。.change() あたりが参考になるかもしれません。

一応、以下のようなサンプルコードを書いてみました。実験室 で実際に動かせます。

<%@ 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>リストコントロール上の選択結果を取得</title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript">
  </script>
  <script type="text/javascript">
  //<![CDATA[
    $(document).ready(function () {

      $("#DropDownList1").change(function () {
        var str = $("#DropDownList1 option:selected").val() +
          " " + 
          $("#DropDownList1 option:selected").text();
          $("#Div1").text(str);
        });

        $("#ListBox1").change(function () {
          var str = "";
          $("#ListBox1 option:selected").each(function () {
            str += $(this).val() + " " + 
            $(this).text() + " ";
          });
          $("#Div2").text(str);
        });

        $("#RadioButtonList1").change(function () {
          var str = 
            $("#RadioButtonList1 input:checked").val() +
            " " +
            $("#RadioButtonList1 input:checked + label").text();
          $("#Div3").text(str);
        });

        $("#CheckBoxList1").change(function () {
          var str = "";
          $("#CheckBoxList1 input:checked").each(function () {
            str += $(this).val() + " " +
              $(this).next().text() + " ";
          });
          $("#Div4").text(str);
        });
      });
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <table style="width: 500px;">
    <tr>
      <td style="vertical-align: top;">
        <asp:DropDownList id="DropDownList1" 
          runat="server">
          <asp:ListItem Value="00" Text="Red" />
          <asp:ListItem Value="01" Text="Green" />
          <asp:ListItem Value="02" Text="Blue" />
        </asp:DropDownList>
      </td>
      <td style="vertical-align: top;">
        <asp:ListBox id="ListBox1" 
          Rows="3" 
          SelectionMode="Multiple" 
          runat="server">
          <asp:ListItem Value="10" Text="Red" />
          <asp:ListItem Value="11" Text="Green" />
          <asp:ListItem Value="12" Text="Blue" />
        </asp:ListBox>    
      </td>
      <td style="vertical-align: top;">
        <asp:RadioButtonList id="RadioButtonList1" 
          runat="server">
          <asp:ListItem Value="20" Text="Red" />
          <asp:ListItem Value="21" Text="Green" />
          <asp:ListItem Value="22" Text="Blue" />
        </asp:RadioButtonList>
      </td>
      <td style="vertical-align: top;">
        <asp:CheckBoxList id="CheckBoxList1" 
          runat="server">
          <asp:ListItem Value="30" Text="Red" />
          <asp:ListItem Value="31" Text="Green" />
          <asp:ListItem Value="32" Text="Blue" />
        </asp:CheckBoxList>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">
        <div id="Div1"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div2"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div3"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div4"></div>
      </td>
    </tr>
  </table>
  </form>
</body>
</html>

----- 2012/11/10 注記追加 -----

.NET 3.5 では、CheckBoxList からレンダリングされる html コードで、input 要素に value 属性が設定されません。その状態で、上記 jQuery のコードで value を取得すると "on" となります。(注: MDN のドキュメント <input type="checkbox"> によると "value 属性が省略された場合は、チェックボックスの既定値は on " とのことです)

実験室は .NET 3.5 なので試してみてください。CheckBoxList のみ on Red とか on Green と表示されるはずです。.NET 4 では問題ありません。上の画像は .NET 4 のものです。

IE8 以前、IE9 でも互換モードでは、ListBox と CheckBoxList をクリックしても、最初は無反応となります。理由は、最初に表示されたときはイベントにハンドラがアタッチされないからです。何度かクリックしているとアタッチされて反応するようになります。理由は不明。ちなみに、Firefox 16.0.2, Chrome 23.0.1271.64 m Safari 5.1.7, Opera 12.02 は問題なかったです。

----- 2013/2/7 追加 -----

先に、IE9 では期待通り動くが IE8 以前では、ListBox と CheckBoxList が、最初のうち無反応と書きました。違いは何かを考えてみると、IE9 では DOM Level 3 Events がサポートされているのに対し、IE8 以前ではサポートされてないことを思い出しました。

試しに、addEventListener メソッドと attachEvent メソッドを使い分けてハンドラ(リスナー)をアタッチするようにしてみました。

その結果、ListBox は期待通り動くようになったものの、RadioButtonList と CheckBoxList が全く無反応になってしまいました。(IE8 以前での話しです。IE9 は問題ありません)

Microsoft が公開しているドキュメント change | onchange event (Internet Explorer) によると、change イベントが発生する条件として以下の記述があります。(← Microsoft の記事はリンク切れになってしまいました。クリックすると MDN の記事 HTMLElement: change event に遷移しますが、それとは内容が異なります)

To invoke this event, do one of the following:

  1. Choose a different option in a select object using mouse or keyboard navigation.
  2. Alter text in the text area and then navigate out of the object.

ということは、RadioButtonList, CheckBoxList はそれぞれ input type=checkbox, input type=radio 要素なので、change イベントは発生しないということになります。

change イベントに代えて click イベントにリスナーをアタッチすることで RadioButtonList, CheckBoxList の選択を変更を捕捉できます。

以下のコードが対応版です。実験室 で実際に動かせます。

オリジナルとの違いは、(1) ListBox については、change イベントにリスナーをアタッチするのを jQuery 任せにせず自分でコードを書いて addEventListener メソッドと attachEvent メソッ ドを使い分けたこと、(2) RadioButtonList, CheckBoxList については、change イベントの代わりに click イベントにリスナーをアタッチしたことです。

なお、なぜ ListBox では jQuery によるリスナーのアタッチがうまくいかず、上記 (1) の操作が必要かは不明です。

<%@ 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 id="Head1" runat="server">
  <title>WebSurfer's Page - 実験室</title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript">
  </script>
  <script type="text/javascript">
  //<![CDATA[
  $(document).ready(function () {
    $("#DropDownList1").change(function () {
      var str = $("#DropDownList1 option:selected").val() +
        " " +
        $("#DropDownList1 option:selected").text();
      $("#Div1").text(str);
    });

    function listenerForListBox() {
      var str = "";
      $("#ListBox1 option:selected").each(function () {
        str += $(this).val() + " " + $(this).text() + " ";
      });
      $("#Div2").text(str);
    }

    var element = document.getElementById("ListBox1");
    if (element.addEventListener) {
      element.addEventListener('change', 
                               listenerForListBox, false);
    } else if (element.attachEvent) {
      element.attachEvent('onchange', listenerForListBox);
    }

    $("#RadioButtonList1").click(function () {
      var str =
        $("#RadioButtonList1 input:checked").val() +
        " " +
        $("#RadioButtonList1 input:checked + label").text();
      $("#Div3").text(str);
    });

    $("#CheckBoxList1").click(function () {
      var str = "";
      $("#CheckBoxList1 input:checked").each(function () {
        str += $(this).val() + " " +
          $(this).next().text() + " ";
      });
      $("#Div4").text(str);
    });
  });
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <table style="width: 500px;">
    <tr>
      <td style="vertical-align: top;">
        <asp:DropDownList id="DropDownList1" 
          runat="server">
          <asp:ListItem Value="00" Text="Red" />
          <asp:ListItem Value="01" Text="Green" />
          <asp:ListItem Value="02" Text="Blue" />
        </asp:DropDownList>
      </td>
      <td style="vertical-align: top;">
        <asp:ListBox id="ListBox1" 
          Rows="3" 
          SelectionMode="Multiple" 
          runat="server">
          <asp:ListItem Value="10" Text="Red" />
          <asp:ListItem Value="11" Text="Green" />
          <asp:ListItem Value="12" Text="Blue" />
        </asp:ListBox>    
      </td>
      <td style="vertical-align: top;">
        <asp:RadioButtonList id="RadioButtonList1" 
          runat="server">
          <asp:ListItem Value="20" Text="Red" />
          <asp:ListItem Value="21" Text="Green" />
          <asp:ListItem Value="22" Text="Blue" />
        </asp:RadioButtonList>
      </td>
      <td style="vertical-align: top;">
        <asp:CheckBoxList id="CheckBoxList1" 
          runat="server">
          <asp:ListItem Value="30" Text="Red" />
          <asp:ListItem Value="31" Text="Green" />
          <asp:ListItem Value="32" Text="Blue" />
        </asp:CheckBoxList>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">
        <div id="Div1"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div2"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div3"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div4"></div>
      </td>
    </tr>
  </table>
  </form>
</body>
</html>

Tags: ,

JavaScript

jQuery Ajax で xml 形式のデータ受け取り

by WebSurfer 17. July 2012 21:37

jQuery Ajax で Web サービスを呼び出し、xml 形式のデータを受け取る場合の話です。

まず、Web サービスのメソッドの戻り値の型の形式として XML を指定するときは、ScriptMethodAttribute 属性 を追加し、ResponseFormat プロパティ を Xml に設定します。さらに、メソッドが XmlDocument オブジェクト を返すようにします。以下のような感じです。

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public XmlDocument GetXmlDocument()
{
    // Xml 形式の文字列を組み立て。
    string _xmlString = CreateXmlString();

    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(_xmlString);
    return xmlDoc;
}

こうしておくと、XmlDocument オブジェクトはサーバーで Xml 形式の文字列にシリアル化され、このメソッドを呼んだクライアントに返されます。また、応答ヘッダには Content-Type: text/xml が含まれるようになります。

ScriptMethod 属性の ResponseFormat プロパティを Xml に設定しておかない場合、Web サービスのメソッドが返すデータの形式は、クライアントからの要求ヘッダの Content-Type の指定によるようです。

クライアントからサーバーへデータを送信する場合、要求ヘッダの Content-Type は、application/x-www-form-urlencoded または application/json のいずれかになるはずです(データを送信しない場合、Content-Type を指定しないこともありますが)。

前者は普通に form データをサーバーに POST する時のデータ形式、後者は Ajax でのデータ交換フォーマットのデファクトスタンダード(?)である JSON 形式です。

要求ヘッダの Content-Type が application/json となっている場合、ScriptMethod 属性の ResponseFormat プロパティを Xml に設定しておかないと、戻り値が Xml 形式にならない(といって、正しい Json 形式にもならない)ので注意してください。

要求ヘッダの Content-Type を設定しない、または application/x-www-form-urlencoded とした場合は、ResponseFormat プロパティの設定に関係なく、戻り値は Xml 形式になります。(ResponseFormat プロパティを Json 設定しても無視されて、戻り値は Xml 形式になります。)

クライアントで Web サービスからのデータを受け取るのは jQuery Ajax の success ハンドラです。jQuery Ajax は、サーバーからの応答ヘッダに含まれる Contetnt-Type を見て success ハンドラに渡すデータの形式を決めます。

jQuery API の解説ページ jQuery.ajax() に次の説明があります。

"The text and xml types return the data with no processing. The data is simply passed on to the success handler, either through the responseText or responseXML property of the jqXHR object, respectively."

上のサンプルに書いたコードの場合、Web サービスからの応答ヘッダに Contente-Type: text/xml が含まれますので、success ハンドラに渡される data は jqXHR.responseXML から取得されます。

jqXHR.responseXML は何かというと、MSDN ライブラリの responseXML property に書いてあるように、XML DOM オブジェクト(ただのシリアル化された文字列ではなく)になります。

シリアル化された文字列を表示したい場合は、IE であれば xml プロパティが使えます。詳しくは、MSDN ライブラリの IXMLDOMDocument/DOMDocument Members を参照してください。

ただし、xml プロパティは IE 専用なので、Mozilla 系のブラウザの場合は以下のように XMLSerializer を使用できます。

function getXmlDocument() {
  $.post("163-ScriptMethodAttribute.asmx/GetXmlDocument",
    function (data, textStatus, jqXHR) {
      $('#output').empty();
      $('#output').text(data.xml || 
        (new XMLSerializer()).serializeToString(data));
    }
  );
}

または、jqXHR.responseText から取得することも可能です。

Tags: , ,

AJAX

jQuery.ajax で form データを送信

by WebSurfer 14. July 2012 16:43

jQuery.ajax で form データを送信する方法です。ちょっとハマったので忘れないように書いておきます。

Fiddler によるキャプチャ画面

例えば、"日本語" と "URL エンコードされるか?" という文字列を送信する場合は以下のようにします。

data: 'aaa=' + '<%=Server.UrlEncode("日本語")%>' + 
    '&bbb=' + '<%=Server.UrlEncode("URL エンコードされるか?")%>'

または、

data: { aaa: '日本語', bbb: 'URL エンコードされるか?' }

後者は、"日本語" および "URL エンコードされるか?" という文字列を自動的に UrlEncode して、前者と同様な form データを作って送信してくれるので、こちらの方がお勧めです。

上の画像は、以下の jQuery Ajax のコードでデータを送信した時、送信データを Fiddler でキャプチャしたものです。URL エンコードされているのが分かります。

$.post("152-jQueryAjaxXml.asmx/GetXml",
    { aaa: '日本語', bbb: 'URL エンコードされるか?' },
    function (data, textStatus, jqXHR) {
        $('#output').text(data.xml);
    }
);

Tags: ,

AJAX

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。ブログ2はそれ以外の日々の出来事などのトピックスになっています。

Calendar

<<  December 2025  >>
MoTuWeThFrSaSu
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar