繰り返しコントロールでビューを作るには

繰り返しコントロールを使って、ビューを作ってみよう。

繰り返しコントロールとは

繰り返しコントロールは、ビューや文書コレクション(DocumentCollection)をデータソースにして、 そこからアイテムを切り出しながら、繰り返し処理を行ってくれる。

ということで、まずはデータソースを紐付ける。データソース定義時にデータソース自体に名前を適当につける。 普通は、Notesビューをデータソースにする。

繰り返しコントロールのデータソース

繰り返しコントロールはソースコードで

繰り返しコントロールは、ソースコードの方が理解しやすいと思う。

ステップ1.繰り返しコントロールにデータソースを定義

データソースを指定すると、ソースコードはこんな感じになる。

  <xp:this.data>
    <xp:dominoView var="DS場所別" viewName="場所別"></xp:dominoView>
  </xp:this.data>
  <xp:repeat id="repeat1" rows="30" value="#{DS場所別}">
  </xp:repeat>
  

<xp:repeat>のvalue="#{DS場所別}"は、繰り返しコントロールのデータソースをDS場所別にしているということ。

ステップ2.データソースから取り出したアイテムを入れる変数を指定

<xp:repeat>にvar="item"を追加すると、データソースから取り出した1個分の要素をitemという変数にいれてくれる。

この場合、itemはNotesView形式のデータソースから切り出した要素なので、NotesXspViewEntryクラスのインスタンスになる。

あとは、<xp:repeat>〜</xp:repeat>の間に、ラベルか何かでitemの任意の情報を表示する処理をかけばいい。

  <xp:this.data>
    <xp:dominoView var="DS場所別" viewName="場所別"></xp:dominoView>
  </xp:this.data>
    <xp:table style="width:80.0%">
    <xp:tr>
      <th>場所</th>
      <th>管理番号</th>
      <th>PCホスト名</th>
    </xp:tr>
      <xp:repeat id="repeat1" rows="30" value="#{DS場所別}" var="item">
        <xp:tr>
          <xp:td>
            <xp:label value="#{javascript:item.getColumnValue('場所')}" id="label1"></xp:label>
          </xp:td>
          <xp:td>
            <xp:label value="#{javascript:item.getColumnValue('管理番号')}" id="label2"></xp:label>
          </xp:td>
          <xp:td>
            <xp:label value="#{javascript:item.getColumnValue('ホスト名')}" id="label3"></xp:label>
          </xp:td>
        </xp:tr>
      </xp:repeat>
    </xp:table>
  

このサンプルの場合、ページャはつけてないので、最大行分表示してしまうとそれ以上のページめくりはできない。

ステップ3. ページャをつける

ページめくりができるように、「ページャ」コントロールを貼り付ける。 ページャコントロールのプロパティに、「添付先」があるので、ここに繰り返しコントロールのIDを指定できるようになっている。

ページャのプロパティ

これだけで、ページめくりが実現できる。

ビュー以外のデータソース

データソースはビューと文書以外にも指定できる。

基本は、配列のように、要素が順番に並んでいるなら何でもデータソースに指定できる。 以下の例は、<xp:repeat>のvalueにDBの情報の配列をセットしている例。

<xp:this.value>は、value="xxx"の別の書き方。 また、<![CDATA[#{javascript:xxxx}]]>は、"#{javascript:xxxx}"と同義になる。ただ、<![CDATA]>の方は、""などをエスケープしなくてもいいので何かと楽。

<![CDATA]>の中に書かれているのは、DBの一覧を取得して、必要な情報を読み出して、list[]にpushしている処理。

LotusScriptをやってた人にはおなじみの処理だけど、sessionはグローバルオブジェクトとして最初から存在しているのがちょっと違うことろ。

  <xp:table style="width:80.0%">
    <xp:tr>
      <th>ファイル名</th>
      <th>ファイルサイズ</th>
      <th>DBタイトル</th>
    </xp:tr>
    <xp:repeat id="repeat1" rows="30" var="item">
      <xp:this.value>
        <![CDATA[#{javascript:
          var list = [];
          var dir:NotesDirectory = session.getDbDirectory(null);
          var db:NotesDatabse = dir.getFirstDatabase(1247); // 1247 = type DATABASE
  
          while(db != null) {
            db_item = [db.getFileName(), db.getSize(), db.getTitle()]
            list.push(db_item)
            db = dir.getNextDatabase();
          }
          return list;
        }]]>
      </xp:this.value>
      <xp:tr>
        <xp:td>
          <xp:label
            value="#{javascript:item[0]}" id="label1">
          </xp:label>
        </xp:td>
        <xp:td>
          <xp:label value="#{javascript:item[1]}" id="label2"></xp:label>
        </xp:td>
        <xp:td>
          <xp:label value="#{javascript:item[2]}" id="label3"></xp:label>
        </xp:td>
      </xp:tr>
    </xp:repeat>
  </xp:table>
  

しかし、JavaScriptだと実にエレガントにかけるもんだなぁ。 VisualBasic亜種のLotusScriptだと、もうヘドが出そうな汚い書き方しかできなかったもんなぁ。

<xp:repeat>のvalueにDominoオブジェクトそのものを入れないように

先ほどの処理では、最初にページを開いた段階で、すべてのデータがいったん<xp:repeat>のvalueにセットされる。 このケースでは、DBの個数に応じて、使用されるメモリサイズが変化する。そのため、DBが少ないうちは問題ないが、DBの数が多くなると、ある時点でメモリが足りなくなる恐れがある。

まぁ、先ほどの例では文字列や数値がセットされるだけなので、たいしたことはないと思うが、以下のように、NotesDatabaseオブジェクトそのものを保持するような設計だと、 たぶんDBの数がある程度増えた時点で、落ちる。 間違っても、NotesDatabaseオブジェクトそのものをlistに入れるようなことをしてはいけない。

以下はまずい設計の例。

  <xp:table style="width:80.0%">
    <xp:tr>
      <th>ファイル名</th>
      <th>ファイルサイズ</th>
      <th>DBタイトル</th>
    </xp:tr>
    <xp:repeat id="repeat1" rows="30" var="item">
      <xp:this.value>
        <![CDATA[#{javascript:
          var list = [];
          var dir:NotesDirectory = session.getDbDirectory(null);
          var db:NotesDatabse = dir.getFirstDatabase(1247); // 1247 = type DATABASE
  
          while(db != null) {
            list.push(db)  // NotesDatabaseそのものをlistに格納
            db = dir.getNextDatabase();
          }
          return list;
        }]]>
      </xp:this.value>
      <xp:tr>
        <xp:td>
          <xp:label
            value="#{javascript:item.getFileName()}" id="label1">
          </xp:label>
        </xp:td>
        <xp:td>
          <xp:label value="#{javascript:item.getSize()}" id="label2"></xp:label>
        </xp:td>
        <xp:td>
          <xp:label value="#{javascript:item.getTitle()}" id="label3"></xp:label>
        </xp:td>
      </xp:tr>
    </xp:repeat>
  </xp:table>