LoginSignup
5
2

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-04-01

大量データを表示する時に一部だけフェッチしたい

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

oj.Collection

Oracle JET を使っている場合 oj.Collection を利用することで簡潔に表現することができます。Cookbookにもoj.Collectionを使ったListViewの例などはありますが、リモートフェッチの詳細は書かれていません。
リモートフェッチがどのように制御されるかについては、oj.Collectionに書かれているものの、この記事を書いている時点ではサンプルがありません。

サンプル

ということで載せておきます。以下はHTML。ojListViewを使用しています。各アイテムはitemTemplateで表現されています。

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となるフィールドを指定してあげています。

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を返すとどうなるかというと・・・

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は暗黙的に次のように解釈しています。

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の構造を受け取るということです。ということで、次のように総件数である totalResults を入れて返すと ojListView などのコンポーネントは正しく解釈してくれます。

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 をスクロールさせると・・・

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
...

上のようにどんどんサーバー側にフェッチリクエストが来てくれます。めでたしめでたし。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2