RepeaterRepeaterをネストさせる(クライアント側で実現)

 

RepeaterRepeaterをネストさせて商品区分別商品リストをタブコントロール形式で表示します。

 

●商品区分別商品リストをタブコントロール形式で表示する (ch67TabbedControl1.aspx)

 

Repeater1Repeater2をネストさせて商品区分別の商品を表示します。Repeater1Categories表を表示するには、パッケージ(CategoryPackage)に登録されているストアドプロシージャ(GetCategories)を使用します。このストアドプロシージャは、Categories表からすべての行(レコード)を抽出します。

 

Repeater2Products表を表示するには、パッケージ(ProductPackage)に登録されているストアドプロシージャ(GetProductsByCategoryID)を使用します。このストアドプロシージャは、パラメータに指定した商品区分IDに該当する商品を抽出します。

 

iSQL*PlusまたはSQL*Plusを起動して、事前にパッケージ仕様部とパッケージ本体部を作成してください。

 

パッケージ仕様部

CategoryPackage.sql

CREATE OR REPLACE PACKAGE CategoryPackage AS

  TYPE rcurCategories IS REF CURSOR;

  PROCEDURE GetCategories(

    orcurCategories OUT rcurCategories);

END CategoryPackage;

 

ProductPackage.sql

CREATE OR REPLACE PACKAGE ProductPackage AS

  TYPE rcurProducts IS REF CURSOR;

  PROCEDURE GetProductsByCategoryID(

    orcurProducts OUT rcurProducts,

    iCategoryID IN NUMBER);

END ProductPackage;

 

 

パッケージ本体部

CategoryPackage.sql

CREATE OR REPLACE PACKAGE BODY CategoryPackage AS

  PROCEDURE GetCategories(

    orcurCategories OUT rcurCategories) IS

  BEGIN

    OPEN orcurCategories FOR

       SELECT * FROM Categories

       ORDER BY CategoryID;

  END GetCategories;

END CategoryPackage;

 

ProductPackage.sql

CREATE OR REPLACE PACKAGE BODY ProductPackage AS

  PROCEDURE GetProductsByCategoryID(

    orcurProducts OUT rcurProducts,

    iCategoryID IN NUMBER) IS

  BEGIN

    OPEN orcurProducts FOR

      SELECT *

      FROM Products

      WHERE CategoryID = iCategoryID

      ORDER BY ProductID;

  END GetProductsByCategoryID;

END ProductPackage;

 

このサンプルでは、以下のノウハウを習得することができます。

 

RepeaterRepeaterをネストさせる方法

RepeaterItemTemplateRepleaterを作成する方法

ItemTemplateにデータ連結式を記述する方法

WebページにJavaScriptを挿入する方法

<div>タグにクライアント側で動作するonclickイベントを登録する方法

onclickイベントにデータ連結式を記述する方法

JavaScriptStyle属性のdisplayプロパティを可視、不可視に書き換える方法

 

 

1. Webフォーム追加

 

ソリューションエクスプローラからフォルダ[ch6]を右クリックして、新規Webフォーム「ch67TabbedControl1.aspx」を追加します。

 

2. Repeater1作成

 

ツールボックスの[Webフォーム]からRepeaterをドラッグ&ドロップします。デザイナにRepeater1のオブジェクトが作成されます。

 

fig6-7-1

図 デザインにRepeater1作成

 

3. Repeater1のテンプレート作成

 

デザイナの最下位から[HTML]タブをクリックして、HTMLビューに切り替えます。Repeater1<asp:Repeater>...</asp:Repeater>の間にHeaderTemplateItemTemplateFooterTemplateを追加します。

 

<asp:Repeater id="Repeater1" runat="server">

  <HeaderTemplate>

    <div id="container" style="width:100%;height:350px">

  </HeaderTemplate>

  <ItemTemplate>

    <div id='h<%# DataBinder.Eval(Container, "ItemIndex")%>'

      onclick='showTopic(<%# DataBinder.Eval(Container, "ItemIndex")%>);'

      style="cursor:pointer;cursor:hand;position:relative;z-index:2;

cccborder-left: solid 1px black;width:20%;background-color:#aaaaaa;

cccborder-right: solid 1px black;border-bottom: solid 1px black;padding:5px;">

      <%# DataBinder.Eval(Container.DataItem, "CategoryName") %>

    </div>

    <div id='d<%# DataBinder.Eval(Container, "ItemIndex")%>' 

      style="overflow:auto;z-index:1;border: solid 1px black;width:80%;

cccposition:absolute;background-color:#eeeeee;padding:5px;display:none;">

      <!--ここにRepeater 2 挿入 -->

    </div>

  </ItemTemplate>

  <FooterTemplate>

    </div>

  </FooterTemplate>

</asp:Repeater>

 

 

. Repeater2作成

 

HTMLビューの最下位から[デザイン]タブをクリックしてデザインビューに切り替えます。ツールボックスの[Webフォーム]からRepeaterをドラッグ&ドロップします。デザイナにRepeater2のオブジェクトが作成されます。

 

fig6-7-2

デザイナにRepeater2作成

 

プロパティウィンドウから[Repeater2]を選択したら、「(DataBindings)」プロパティを選択してiconRightArrowをクリックします。「Repeater2データ連結」が表示されたら、「連結可能プロパティ」から[DataSource]を選択します。「DataSourceの連結」から[カスタム連結式]を選択したら、テキストボックスに以下の連結式を入力します。

 

GetProductsByCategoryID(DataBinder.Eval(Container.DataItem, "CategoryID"))

 

[OK]をクリックして「データ連結」を閉じます。

 

 

5. Repeater2のテンプレート作成

 

デザイナの最下位から[HTML]タブをクリックして、HTMLビューに切り替えます。Repeater2<asp:Repeater> ...</asp:Repeater>の間にHeaderTemplateItemTemplateFooterTemplateを追加します。

 

<asp:Repeater id="Repeater2" runat="server"

  DataSource='<%# GetProductsByCategoryID(DataBinder.Eval(Container.DataItem, "CategoryID")) %>'>

<HeaderTemplate>

    <ul>

  </HeaderTemplate>

  <ItemTemplate>

    <li>

      <%# DataBinder.Eval(Container.DataItem, "ProductName") %>

      <%# DataBinder.Eval(Container.DataItem, "UnitPrice", " ({0:c0})") %>

    </li>

  </ItemTemplate>

  <FooterTemplate>

    </ul>

  </FooterTemplate>

</asp:Repeater>

 

<asp:Repeater id="Repeater2">...</asp:Repeater>を選択したら、右クリックから[切り取り]を選択します。マウスを「<!--ここにRepeter2挿入 -->」の直後に移動したら、右クリックから[貼り付け]を選択します。これで、Repeater1Repeater2がネストされます。

 

6. JavaScript挿入

 

HTMLビューの<head>...</head>の間に、以下のJavaScriptを追加します。

 

<script language="JavaScript">

  var lastSelectedNum = -1;

  var totalCount = <%=mintTotalCount%>;

   

  function showTopic(num) {

    if (lastSelectedNum >= 0) {

      var lastHeader = document.getElementById('h' + lastSelectedNum);

      var lastDetails = document.getElementById('d' + lastSelectedNum);

       

      lastHeader.style.backgroundColor = '#aaaaaa';

      lastHeader.style.borderRightStyle = 'solid';

      lastDetails.style.display = 'none';

    }      

      

    var header = document.getElementById('h' + num);

    var details = document.getElementById('d' + num);

     

    header.style.backgroundColor = '#eeeeee';

    header.style.borderRightStyle = 'none';

    details.style.display = 'inline';

     

    lastSelectedNum = num;

  }

   

  function setInitialPositions() {

    var topHeader = document.getElementById('h0');

    var container = document.getElementById('container');

    var maxHeight = -1;

     

    topHeader.style.borderTopStyle = 'solid';

    topHeader.style.borderTopColor = 'black';

    topHeader.style.borderTopWidth = '1px';

    for (var i = 0; i < totalCount; i++){

      var details = document.getElementById('d' + i);

      details.style.top = getAscendingTops(container);

      details.style.left = getAscendingLefts(container) + topHeader.clientWidth + 1;

      details.style.height = '100%';  

      if (!container.height) {        

        details.style.display = 'inline';

        if (details.clientHeight > maxHeight) maxHeight = details.clientHeight;

          details.style.display = 'none';

      }

    }    

    if (!container.height){

        container.style.height = maxHeight + 5;

    }

  }

   

  function getAscendingTops(elem){

    if (elem==null)

      return 0;

    else {

      return elem.offsetTop+getAscendingTops(elem.offsetParent);

    }

  }

 

  function getAscendingLefts(elem){

    if (elem==null)

      return 0;

    else {

      return elem.offsetLeft+getAscendingLefts(elem.offsetParent);

    }

  }

</script>

 

fig6-7-3

<head>...</head>タグの間にJavaScript挿入

 

</form>タグの直前に以下のJavaScriptを追加します。

 

<script language="JavaScript">

  setInitialPositions();

  showTopic(0);

</script>

 

 

fig6-7-4

</form>タグの直前にJavaScript挿入

 

7. コードビューに切り替え

 

メニューバーから[表示][コード]を選択してコードビューに切り替えます。クラスモジュールの先頭に、以下のImportsステートメントを追加します。

 

Imports System.Data

Imports Oracle.DataAccess.Client

Imports Oracle.DataAccess.Types

 

Page_Loadイベントの直前に、変数mintTotalCountを追加します。

 

Public mintTotalCount As Integer

 

Page_Loadイベントに、以下のコードを追加します。

 

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)

cccHandles MyBase.Load

  BindCategories()

End Sub

 

クラスモジュールの最後に、Sub BindCategoriesFunction GetCategoriesFunction GetProductsByCategoryIDを追加します。

 

Private Sub BindCategories()

  Repeater1.DataSource = GetCategories()

  Repeater1.DataBind()

  mintTotalCount = Repeater1.Items.Count

End Sub

 

Private Function GetCategories() As OracleDataReader

  Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))

  Dim cmd As New OracleCommand("CategoryPackage.GetCategories", con)

 

  con.Open()

  With cmd

    .CommandType = CommandType.StoredProcedure

    .Parameters.Add("1", OracleDbType.RefCursor, ParameterDirection.Output)

  End With

  Return cmd.ExecuteReader(CommandBehavior.CloseConnection)

End Function

 

Public Function GetProductsByCategoryID(ByVal intCategoryID As Integer) As DataTable

  Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))

  Dim da As New OracleDataAdapter

  Dim cmd As New OracleCommand("ProductPackage.GetProductsByCategoryID", con)

  Dim dt As New DataTable

 

  With cmd

    .CommandType = CommandType.StoredProcedure

    .BindByName = True

    .Parameters.Add("orcurProducts", OracleDbType.RefCursor, ParameterDirection.Output)

    .Parameters.Add("iCategoryID", OracleDbType.Int32).Value = intCategoryID

  End With

  da.SelectCommand = cmd

  da.Fill(dt)

  Return dt

End Function

 

8. ブラウザに表示

 

ソリューションエクスプローラから[ch67TabbedControl1.aspx]を右クリックしてブラウザに表示します。Repeater1Categories表(商品区分)が表示されます。Repeater1から商品区分をクリックすると、Repeater2に商品区分に該当するProducts表(商品)が表示されます。

 

fig6-7-5

商品区分をクリックすると該当する商品が表示される

 

 

  解説

 

このサンプルはRepeater1ItemTemplateRepeater2をネストさせて、商品区分別の商品をタブコントロール形式で表示しています。

 

<asp:Repeater id="Repeater1" runat="server">

  <HeaderTemplate>...</HeaderTemplate>

  <ItemTemplate>

    <asp:Repeater id="Repeater2" runat="server">

      <HeaderTemplate>...</HeaderTemplate>

      <ItemTemplate>...</ItemTemplate>

      <FooterTemplate>...</FooterTemplate>

    </asp:Repeater>

   </ItemTemplate>

  <FooterTemplate>...</FooterTemplate>

</asp:Repeater>

 

Page_Loadイベントでは、BindCategoriesメソッドを実行してRepeater1Categories表のDataReaderをバインドします。

 

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)

 Handles MyBase.Load

  BindCategories()

End Sub

 

BindCategoriesメソッドは、GetCategoriesメソッドを実行してCategories表のDataReaderオブジェクトを作成します。Repeater1オブジェクトのDataSourceプロパティにCategories表のDataReaderオブジェクトを設定したら、DataBindメソッドを実行してバインドします。Repeater1DataBindメソッドを実行すると、Repeater2DataBindメソッドも自動的に実行されます。

 

Private Sub BindCategories()

  Repeater1.DataSource = GetCategories()

  Repeater1.DataBind()

  mintTotalCount = Repeater1.Items.Count

End Sub

 

GetCategoriesメソッドは、OracleCommandオブジェクトのExecuteReaderメソッドを実行して、Categories表のDataReaderオブジェクトを生成して返します。ExecuteReaderメソッドの引数に、CommandBehavior.CloseConnectionを指定すると、DataReaderを閉じたときにOracleConnectionCloseメソッドを自動的に実行します。

 

Private Function GetCategories() As OracleDataReader

  Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))

  Dim cmd As New OracleCommand("CategoryPackage.GetCategories", con)

 

  con.Open()

  With cmd

    .CommandType = CommandType.StoredProcedure

    .Parameters.Add("1", OracleDbType.RefCursor, ParameterDirection.Output)

  End With

  Return cmd.ExecuteReader(CommandBehavior.CloseConnection)

End Function

 

Repeater1ItemTemplateには、データ連結式を記述してCategories表のCategoryName(商品区分名)をバインドしています。<div>タグのid属性に「id='h<%# DataBinder.Eval(Container, "ItemIndex")%>'」のようにデータ連結式を記述して「id=h1, id=h2, id=h3...」のようなidを生成します。

 

同様に、「id='d<%# DataBinder.Eval(Container, "ItemIndex")%>'」のデータ連結式は、「id=d1, id=d2, id=3...」のようなidを生成します。

 

<div>タグのidは、Repeater2を可視、不可視に切り替えるときに参照します。Repeater2を可視状態に切り替えるには、<div>タグのstyle属性のdisplayプロパティに「inline」を設定します。Repeater2を不可視状態に切り替えるには、displayプロパティに「none」を設定します。

 

Repeater1の「商品区分名」をクリックしたときに、Repeater2を可視状態に切り替えるには、<div>タグにクライアント側のブラウザで実行されるonclickイベントと登録します。

 

<div id='h<%# DataBinder.Eval(Container, "ItemIndex")%>'

   onclick='showTopic(<%# DataBinder.Eval(Container, "ItemIndex")%>);'

   style="...">

 

Repeater1の「商品区分名」をクリックすると、onclickイベントが発生してJavaScriptshowTopic()関数が実行されます。

 

<asp:Repeater id="Repeater1" runat="server">

  <HeaderTemplate>

    <div id="container" style="width:100%;height:350px">

  </HeaderTemplate>

  <ItemTemplate>

    <div id='h<%# DataBinder.Eval(Container, "ItemIndex")%>'

      onclick='showTopic(<%# DataBinder.Eval(Container, "ItemIndex")%>);'

      style="...">

      <%# DataBinder.Eval(Container.DataItem, "CategoryName") %>

    </div>

    <div id='d<%# DataBinder.Eval(Container, "ItemIndex")%>' 

      style="...">

      <!--ここにRepeater 2 挿入 -->

    </div>

  </ItemTemplate>

  <FooterTemplate>

    </div>

  </FooterTemplate>

</asp:Repeater>

 

showTopic関数の引数には、<div>タグのID番号を指定します。showTopic関数は、すでに表示(可視)されている<div>タグのstyle属性のdisplayプロパティに「none」を設定して不可視にします。そして、今回選択した<div>タグのstyle属性のdisplayプロパティに「inline」を設定して可視に切り替えます。

 

style属性のdisplayプロパティを「none」、「inline」に切り替える処理は、クライアントのブラウザで実行しますのでWebページがポストバックされません。このように、ブラウザ側で可視/不可視の切り替えを行うと、画面のチラツキがなく使い勝手の良いユーザーインタフェースを構築することができます。ただし、JavaScriptを利用すると、ブラウザによっては正常に動作しないことがありますので適用ブラウザを明確にする必要があります。なお、このサンプルで使用しているJavaScriptは、Internet Explorer 6.xを使用することを前提としています。その他のブラウザを使用したときは、動作が保証されません。

 

function showTopic(num) {

    if (lastSelectedNum >= 0) {

      var lastHeader = document.getElementById('h' + lastSelectedNum);

      var lastDetails = document.getElementById('d' + lastSelectedNum);

       

      lastHeader.style.backgroundColor = '#aaaaaa';

      lastHeader.style.borderRightStyle = 'solid';

      lastDetails.style.display = 'none';

    }

    var header = document.getElementById('h' + num);

    var details = document.getElementById('d' + num);

     

    header.style.backgroundColor = '#eeeeee';

    header.style.borderRightStyle = 'none';

    details.style.display = 'inline';

    lastSelectedNum = num;

}

 

Repeater2DataSourceプロパティには、データ連結式を記述してProducts表のDataTableをバインドしています。GetProductsByCategoryIDメソッドは、Products表から商品区分IDに該当する行(レコード)をDataTableに格納して返します。GetProductsByCategoryIDメソッドの引数には、Categories表のCategoryID(商品区分ID)を指定します。

 

Repeater2ItemTemplateでは、データ連結式でProducts表のProductName(商品名)とUnitPrice(単価)を表示しています。単価をバインドするときの書式「{0:c0}」は、通貨型で小数点以下の桁数を「0」にすることを意味します。

 

<asp:Repeater id="Repeater2" runat="server"

  DataSource='<%# GetProductsByCategoryID(DataBinder.Eval(Container.DataItem, "CategoryID")) %>'>

<HeaderTemplate>

    <ul>

  </HeaderTemplate>

  <ItemTemplate>

    <li>

      <%# DataBinder.Eval(Container.DataItem, "ProductName") %>

      <%# DataBinder.Eval(Container.DataItem, "UnitPrice", " ({0:c0})") %>

    </li>

  </ItemTemplate>

  <FooterTemplate>

    </ul>

  </FooterTemplate>

</asp:Repeater>