JET+oj.Collectionを使用したリモートフェッチ

# 大量データを表示する時に一部だけフェッチしたい
絞り込み前のデータを表示せざるを得ないリストなどでは、どうせ表示は一部しかできないので、表示に必要な部分だけをフェッチしておきたいものです。例えば1000件のアイテムのうち最初のフェッチは10件くらいでもいい時が多いですよね。

## oj.Collection
[Oracle JET](http://www.oracle.com/webfolder/technetwork/jet/index.html) を使っている場合 oj.Collection を利用することで簡潔に表現することができます。Cookbookにも[oj.Collectionを使ったListViewの例](http://www.oracle.com/webfolder/technetwork/jet/uiComponents-listView-collectionListView.html)などはありますが、リモートフェッチの詳細は書かれていません。
リモートフェッチがどのように制御されるかについては、[oj.Collection](http://www.oracle.com/webfolder/technetwork/jet/jsdocs/oj.Collection.html#fetchSize)に書かれているものの、この記事を書いている時点ではサンプルがありません。
### サンプル
ということで載せておきます。以下はHTML。[ojListView](http://www.oracle.com/webfolder/technetwork/jet/uiComponents-listView-staticListView.html)を使用しています。各アイテムはitemTemplateで表現されています。

```html:list.html
<ul id="itemList" aria-label="item list using oj.collection" style="height:100%" 
  data-bind="ojComponent: {
           component: 'ojListView',
                data: itemDataSource,
                item: {template: 'item_template'},
       selectionMode: 'single',
      rootAttributes: {style: 'width:100%;height:200px;overflow-x:hidden'},
        scrollPolicy: 'loadMoreOnScroll',
 scrollPolicyOptions: {fetchSize: 3}
}">
</ul>

<script type="text/html" id="item_template">
 <li data-bind="attr: {id: itemId}">
   <div class="oj-flex" style="flex-wrap: nowrap">
     <div class="oj-flex-item">
       <div>
         <strong data-bind="text: itemName"/>
         <span data-bind="text: itemDesc"/>
       </div>
     </div>
   </div>
 </li>
</script>
```
以下が対応するJavaScriptです。``oj.Model.extend``の部分では、受信したデータに重複があった場合に重複排除ができるようにIDとなるフィールドを指定してあげています。

```js:list.js
define(['ojs/ojcore', 'knockout', 'jquery', 'ojs/ojknockout',
'promise', 'ojs/ojlistview', 'ojs/ojcollectiontabledatasource', 'ojs/ojmodel'],
  function (oj, ko, $) {
    function ListViewModel() {
      var self = this;
      var itemModel = oj.Model.extend({
        idAttribute: 'itemId'
      });
      var itemCollection = new oj.Collection(null, {
        url: 'http://localhost:8080/api/item/list',
        fetchSize: 3,
        model: itemModel
      });
      self.itemDataSource = new oj.CollectionTableDataSource(itemCollection);
    }
    return new FilterViewModel();
  }
);
```

itemDataSourceに基づいてojListViewが描画されます。このとき、fetchSizeが3なので、最初は``http://localhost:8080/api/item/list?totalResults=true&limit=3&offset=0``というリクエストがサーバに送信されます。offset がゼロで limit が3ということは最初の3個ということですね。totalResults=true というのは、総件数を返してね！という意味です。

このリクエストに素直に次のような配列のみのJSONを返すとどうなるかというと・・・

```json:simple.json
[
{"itemId" : 1, "itemName" : "1番目", "itemDesc" : "1番目だよ"},
{"itemId" : 2, "itemName" : "2番目", "itemDesc" : "2番目だよ"},
{"itemId" : 3, "itemName" : "3番目", "itemDesc" : "3番目だよ"}
]
```
表示は正しくされるものの、残念ながらスクロールダウンしても4件目をフェッチしてくれることはありません。なぜなら、総件数を返していないからです。
ということで総件数をJSONで返したいのですが、その構造はどうしたらいいんだろう？となります。
実は、Arrayを返すと、oj.Collectionは暗黙的に次のように解釈しています。

```json:simple-extend.json
{ "models" : [
{"itemId" : 1, "itemName" : "1番目", "itemDesc" : "1番目だよ"},
{"itemId" : 2, "itemName" : "2番目", "itemDesc" : "2番目だよ"},
{"itemId" : 3, "itemName" : "3番目", "itemDesc" : "3番目だよ"}
]}
```
modelsが追加されていますね。これは、[oj.Collection](http://www.oracle.com/webfolder/technetwork/jet/jsdocs/oj.Collection.html#fetchSize)の構造を受け取るということです。ということで、次のように総件数である totalResults を入れて返すと ojListView などのコンポーネントは正しく解釈してくれます。

```json:simple-extend-with-total.json
{ "totalResults" : 1000,
  "models" : [
{"itemId" : 1, "itemName" : "1番目", "itemDesc" : "1番目だよ"},
{"itemId" : 2, "itemName" : "2番目", "itemDesc" : "2番目だよ"},
{"itemId" : 3, "itemName" : "3番目", "itemDesc" : "3番目だよ"}
]}
```
表示させた listView をスクロールさせると・・・

```bash:access.log
http://localhost:8080/api/item/list?totalResults=true&limit=3&offset=0
http://localhost:8080/api/item/list?totalResults=true&limit=3&offset=3
http://localhost:8080/api/item/list?totalResults=true&limit=3&offset=6
http://localhost:8080/api/item/list?totalResults=true&limit=3&offset=9
...
```
上のようにどんどんサーバー側にフェッチリクエストが来てくれます。めでたしめでたし。