SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

親子データを表示するタブ付きインターフェイスの作成

JavaScriptとRepeaterコントロールを組み合わせたインターフェイスの実装

  • このエントリーをはてなブックマークに追加

この記事では、親子関係にある情報を段階的に表示できるタブ付きインターフェイスの実装方法を紹介します。クライアント側JavaScriptをRepeaterコントロールと組み合わせ、適切な書式で生成されるマークアップにデータをレンダリングすることによって、このインターフェイスを実現します。

  • このエントリーをはてなブックマークに追加

はじめに

 前回の記事『Creating Collapsible Detail Regions in a Repeater』では、いくつかのクライアント側JavaScriptとHTML、それにRepeaterコントロールを使って、大量の情報を管理する方法を紹介しました(Repeaterを使った折りたたみ可能な領域のライブデモをご覧ください)。先週の記事を書いた後、このコンセプトを発展させて「もっと美しい」ユーザインターフェイスを提供するにはどうすればよいかを考えました。私が絵画や芸術的なものに心を傾ける人間でないことは率先して認めますが、美しいインターフェイスに仕上げようとする取り組みは、共有する価値があると思います(今回のライブデモをご覧ください)。

 今回は、親子関係のあるデータを表示するための「タブ付きインターフェイス」の実現方法を紹介したいと思います(前回のRepeaterによる折りたたみ可能な領域のサンプルと同じように、特定のアイテムについて詳細情報を表示するものです)。このインターフェイスは、左側に縦に並んだ一連のタブにリストされる親アイテムと、その右側に子データとして表示される各アイテムの詳細情報を持ちます。クリックによって親アイテムのタブを「選択」すると、その詳細情報が右側のペインに表示されます。

 このインターフェイスの最終目標は、Visual Studio .NETのツールボックスからWebコントロールをドロップするだけでタブ付きインターフェイスを作り出せる、カスタムのASP.NETサーバコントロールを開発することです。しかし、このプロジェクトの完了までには時間がかかりそうなので、まずは現時点で実現できているRepeaterとクライアント側のスクリプトおよびマークアップを紹介しておきたいと思います。そう考えた理由は2つあります。1つは、このインターフェイスの外観をサイトに組み込んでもらうことで皆さんのお役に立てれば、と思ったことです。もう1つは、このクライアント側のスクリプトとマークアップはかなり活用できそうだからです。Internet Explorerでは、見た目にも素晴らしいものになります。しかし、FireFoxでは、機能はするものの、満足のいく見栄えとはとても言えません(まだ、IEとFireFox以外のブラウザではテストしていません)。私よりもCSSとDHTMLの経験のある方から、この状況の改善に役立つアドバイスをいただけるのではないかと期待しています。

タブを配置する

 話を続ける前に、インターフェイスの外観を知ってもらうためにぜひライブデモをご覧になってください。

 タブ付きインターフェイスを生成するためのクライアント側マークアップを作成するにあたり、生成するHTML内では、親と子の情報がひと続きになるようにしたいと考えました。というのは、Repeaterコントロールを使って、親と子のデータを一緒に取り込むことを想定していたからです。先週の記事で紹介した、折りたたみ可能な領域のRepeaterにおける、簡略化した情報と詳細な情報へのアクセス方法と同様の考え方です。要するに、次のような宣言の構文を備えたRepeaterを想定していたわけです。

<asp:Repeater runat="server" ...>
  <ItemTemplate>
    ... render parent (or abbreviated) information ...
    
    ... render child (or detailed) information ...
  </ItemTemplate>
</asp:Repeater>

 こうしたRepeaterを使うと、ページにレンダリングされるHTMLは次のようになります。

... markup for parent (or abbreviated) information for item 1...
... markup for child (or detailed) information for item 1...

... markup for parent (or abbreviated) information for item 2...
... markup for child (or detailed) information for item 2...

    ...

... markup for parent (or abbreviated) information for item N...
... markup for child (or detailed) information for item N...

 このマークアップを使って、ページの各要素をどのようにして求められる形に配置するかが課題でした。これに対しては、一連の親(または簡略化した)タイトルが与えられた場合、子(または詳細化した)情報用マークアップのCSSプロパティdisplaynoneに設定することによって、詳細情報をうまく非表示にすることができました。これこそ私が求めていたものです。また、子(または詳細)情報を表示するときに、その領域の左上隅が、一番上の親タブの右上隅にぴったり重なるようにフラッシュさせることも課題でした。この課題の解決に効果がありそうだと私が考えた唯一のアプローチは、絶対位置の利用でした。

 このマークアップはすべて、<div>タグで囲まれます。タブと子(または詳細)データを配置するために、クライアント側のJavaScript関数setInitialPositions()を作成しました。この関数はページを完全に読み込んだ後に呼び出され、次の計算式を使ってタブと子(または詳細)ペインの絶対位置を設定します。

  • 詳細情報の上座標 = その情報を含む<div>の計算された上座標
  • 詳細情報の左座標 = その情報を含む<div>の計算された左座標 + タブの幅 + 1

 各情報を含む<div>において高さが明示的に設定されない場合、setInitialPositions()関数は、詳細情報のアイテムのうち最大の高さを求めて、その<div>の高さに割り当てます(これにより、すべての子または詳細アイテムは、各自がどれだけの情報を持っているかに関係なく、最も大きな子または詳細アイテムの高さに揃えられます)。詳細情報を含む<div>の上座標と左座標を求めるには、2つの再帰関数getAscendingTops(element)getAscendingLefts(element)を使います。これらの関数は、渡された要素に含まれるHTML要素の集合を調べ、それぞれ上オフセットと左オフセットを足し合わせていくものです。この手法の詳細については、『Determining the Location of a Nonpositioned Element』を参照してください。私が提供しているフリーのオープンソース部品、ASP.NETメニューコントロールskmMenuでは、この手法を利用しています。

親タブのクリック時に子データの表示と非表示を切り替える

 親のタブがクリックされたときに、対応する子のデータを表示する必要があります。この動作は、クライアント側のonclickイベントハンドラを、JavaScript関数showTopic(child/details index)の呼び出しを行うそれぞれのタブに追加することで実現します。child/details indexは、子または詳細データに与えられたインデックスを表します。このインデックスには、1番目の親タブに対応する子(または詳細)データには0、2番目の親タブに対応するものには1、というように値が割り当てられます。showTopic()関数が行う処理は、次のとおりです。

  1. displayプロパティをnoneに設定することによって、現在選択されている子(または詳細)情報を非表示にする
  2. 現在選択されているタブをリセットして「選択されていない」状態にする
  3. displayプロパティをinlineに設定することによって、クリックされたタブに対応する子(または詳細)情報を表示する
  4. 背景色と右側の境界線の色を変えることにより、クリックされたタブを「選択されている」状態にする

データベースのデータをタブ付きインターフェイスに表示する

 データベース内の、親と子、または簡略化と詳細化の関係にある情報をタブ付きインターフェイスに表示するには、次の処理を行う必要があります。

  1. 必要なクライアント側JavaScript関数を用いてASP.NETページを作成する
  2. テンプレート内に適切にマークアップされたコンテンツを持つRepeaterを追加する
  3. 適切なデータベースのデータをRepeaterにバインドするサーバ側コードを追加する

 では、このRepeaterで必要になるマークアップを見てみましょう。基本的に、このRepeaterでは、1アイテムにつき2つの<div>要素が必要になります。1つは親情報または簡略化された情報を含むもの、もう1つはこうした特定の親(または簡略化)情報に対応する子(または詳細)情報を含むものです。先ほど説明したように、タブ付きインターフェイスのマークアップ全体は、<div>タグの内部に置かれます。このマークアップは、Repeaterを宣言する構文の近くで定義するか、RepeaterHeaderTemplateFooterTemplateの内部に挿入することができます。この場合、Repeaterのテンプレートとマークアップは、次のようになります。

<asp:Repeater runat="server" id="rptTabInterface">
  <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;
                border-left: solid 1px black;
                width:20%;background-color:#aaaaaa;
                border-right: solid 1px black;
                border-bottom: solid 1px black;padding:5px;">
      ... Parent/abbreviated data goes here ...
    </div>
  
    <div id='d<%# DataBinder.Eval(Container, "ItemIndex")%>' 
         style="overflow:auto;z-index:1;
                border: solid 1px black;width:80%;
                position:absolute;background-color:#eeeeee;
                padding:5px;display:none;">
      ... Child/detail data goes here ...
    </div>
  </ItemTemplate>
  
  <FooterTemplate>
    </div>
  </FooterTemplate>
</asp:Repeater>

 上記のサンプルでば、マークアップを含む<div>が、HeaderTemplateFooterTemplateの内側に置かれています。HeaderTemplateにおいてheightが350ピクセルに設定されていることに注意してください。この設定により、子(または詳細)データの表示に必要な領域の大きさに関係なく、タブ付きインターフェイスの高さはきっちり350ピクセルになります。表示領域の高さが350ピクセルを超える子(または詳細)情報には、垂直スクロールバーが付きます。この<div>タグの中でheightの明示的な設定を省略すると、タブ付きインターフェイスの高さは、最大の子(または詳細)データが必要とする値に設定されます。

 ItemTemplateには、2つの<div>要素があります。1つ目は、idhIndexに等しい要素で、親(または簡略化)情報が入っています。このIndexは、現在のRepeaterItemのインデックスを表します。この1つ目の<div>タグの中に置かれるコンテンツは、対応するタブに表示されます。ItemTemplate内の2つ目の<div>要素には、子(または詳細)データが入っていて、dIndexに等しいidを持っています(こうしたidは、HTML要素のスタイルの参照と変更をプログラムによって行うためにクライアント側の関数で使用されるため、注意が必要です)。

 ItemTemplate内のどちらの<div>要素にも、背景色、境界の動作、パディング、オーバフロー時の動作などを定義するスタイルが含まれています。background-colorなど、これらの設定のいくつかを調整すれば、このタブ付きインターフェイスを読者ご自身のサイト向けにカスタマイズできます。詳細アイテムの位置を明示的に決定し、クリックされたタブに応じてスタイルを変更するという作業のすべては、JavaScript関数によって処理されます。この動作の確認(およびソースコードのコピー)には、ライブデモを活用してください。

 最後に1つ、重要なことですが、ページの下部でsetInitialPositions()関数の呼び出しを行います。また、showTopic(0)を呼び出すことによって、最初のタブを自動的に表示することもできます。この表示を行うには、Repeaterの後に次のような<script>ブロックを追加します。

<script language="JavaScript">
  setInitialPositions();
  showTopic(0);
</script>

まとめ

 この記事では、親と子、または簡略化と詳細化の関係にある情報を段階的に表示できるタブ付きインターフェイスの実装方法を紹介しました。クライアント側JavaScriptをRepeaterコントロールと組み合わせ、適切な書式で生成されるマークアップにデータをレンダリングすることによって、このインターフェイスを実現しました。プロジェクトとしての最終目標は、ASP.NETのWebページにコントロールをドラッグアンドドロップするだけで、このインターフェイスを作り上げることができる、カスタムのサーバコントロールを作成することです。今回のところは、とりあえず、ライブデモをご覧いただき、そのコードをコピーして(カスタマイズできる場所はいくつかありますが)そのまま貼り付け、読者ご自身のサイトにこのタブ付きインターフェイスを実装してみてください。

 それでは、ハッピープログラミング!

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Scott Mitchell(Scott Mitchell)

http://www.4guysfromrolla.com/ScottMitchell.shtml

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/206 2006/01/06 20:39

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング