2020.06.23

B2B Commerce標準ページネーションの活用

  • このエントリーをはてなブックマークに追加
  • follow us in feedly
gettyimages (16617)

はじめまして、テラスカイの范です。
SalesforceのB2B Commerce はデフォルトの標準設定のまますぐに使用することができますが、多くの場合、拡張が必要になります。
管理パッケージであるこのアプリケーションの動作を変更するには、カスタムコードを使用して拡張と上書きを行いますが、今回はB2BCommerceの標準ページネーションを拡張する方法を紹介します。

B2B Commerceの概要については、下記の記事をご参照ください。

はじめに

B2B Commerceのテクノロジースタックを簡単に説明します。
B2BCommerceはユーザーインターフェイスを備えたJavaScriptに広く依存しています。基本的に、次のテクノロジースタックに基づいて構築されています。
- jQuery (base, UI, and validation)
- Backbone
- Bootstrap
- Handlebars
他のライブラリも使用されますが、これらの4つはアーキテクチャの中核を形成します。
ページネーションを実装する前に、以下の手順で商品一覧メニューを作成します。
1、サブスクライバーページを作成します。Visualforceページ名は「productList」とします。
2、サブスクライバーページにメニューリンクを追加します。
3、CC管理でメニューキャッシュを更新します。

これで商品一覧ページの準備ができたので、さっそくページネーションの実装に入ります。

実装

まずはページネーションのコンポネントを用意します。
ページネーションのビューとテンプレートはB2BCommerceの標準のものをそのままで利用します。
<apex:component >
    <apex:attribute name="eLName" type="String" description="DOM object name"/>
    <script type="text/javascript">
        jQuery(function($) {
            CCRZ.views.paginationView = CCRZ.CloudCrazeView.extend({
                templateDesktop: CCRZ.util.template('paginationTmpl'),
                desktopEl: '{!eLName}',
                events: {
                    'click .firstAction': 'firstPage',
                    'click .lastAction': 'lastPage',
                    'click .previousAction': 'previousPage',
                    'click .nextAction': 'nextPage',
                    'click .gotoPage': 'gotoPage',
                    'change .sizeAction': 'changePageSize',
                    'click .resortAction': 'resort'
                },
                init: function () {
                    this.listenTo(this.model, 'reset', this.render);
                },
                hostRendered: function (context, options) {
                    if (options) {
                        this.hostView = options.hostView;
                    }
                    this.render();
                },
                withinViewChange: false,
                managedSubView: true,
                preViewChanged: function () {
                    this.withinViewChanged = true;
                },
                preRender: function () {
                    this.$el.html('');
                    v = this;
                    v.model.state.slidingWindowSize = parseInt(CCRZ.getPageConfig('pgbl.WndSz', '3'));
                    v.model.state.currentSlidingWindow = Math.floor((v.model.state.currentPage - 1) / v.model.state.slidingWindowSize) + 1;
                    v.model.state.startPage = (v.model.state.currentSlidingWindow - 1) * v.model.state.slidingWindowSize + 1;
                    if ((v.model.state.currentSlidingWindow * v.model.state.slidingWindowSize) <= v.model.state.totalPages) {
                        v.model.state.endPage = (v.model.state.currentSlidingWindow) * v.model.state.slidingWindowSize;
                    } else {
                        v.model.state.endPage = v.model.state.totalPages;
                    }
                    v.model.state.hasPrevious = v.model.hasPreviousPage();
                    v.model.state.hasNext = v.model.hasNextPage();
                    v.model.state.startItem = (v.model.state.currentPage - 1) * v.model.state.pageSize + 1;

                    if ((v.model.state.currentPage * v.model.state.pageSize) <= v.model.state.totalRecords) {
                        v.model.state.endItem = (v.model.state.currentPage) * v.model.state.pageSize;
                    } else {
                        v.model.state.endItem = v.model.state.totalRecords;
                    }

                    var itemsPerPage = CCRZ.getPageConfig('pgbl.itmPerP', '10,25,50,75');
                    v.model.state.itemsPerPagePLValues = itemsPerPage.split(",");
                    for (var i = 0; i < v.model.state.itemsPerPagePLValues.length; i++) {
                        v.model.state.itemsPerPagePLValues[i] = parseInt(v.model.state.itemsPerPagePLValues[i], 10);
                    }
                },
                renderDesktop: function () {
                    v.setElement($(this.desktopEl));
                    v.$el.html(v.templateDesktop(v.model.state));
                },
                postRender: function () {
                    if (!this.withinViewChanged && this.hostView) {
                        var eventName = 'pagination:' + this.hostView + ':rendered';
                        CCRZ.pubSub.trigger(eventName, this);
                        CCRZ.console.log('trigger=' + eventName + ' context=' + this);
                    }
                    this.withinViewChanged = false;
                },
                firstPage: function () {
                    this.model.getFirstPage();
                },
                previousPage: function () {
                    this.model.getPreviousPage();
                },
                nextPage: function () {
                    this.model.getNextPage();
                },
                lastPage: function () {
                    this.model.getLastPage();
                },
                setSorting: function (sortKey, asc) {
                    this.model.setSorting(sortKey, asc);
                    this.model.fullCollection.sort();
                },
                gotoPage: function (event) {
                    var pageNum = $(event.target).data('id');
                    this.model.getPage(pageNum);
                },
                changePageSize: function (event) {
                    v = this;
                    var pSize = parseInt($(event.currentTarget).val());
                    v.model.setPageSize(pSize, {
                        first: true
                    });
                },
                resort: function (event) {
                }
            });
        });
    </script>

    <script id="paginationTmpl" type="text/template">
        <div class="panel panel-default cc_panel cc_paginator">
            <div class="panel-body cc_body">
                <div class="row">
                    <div class="col-xs-4">
                        <p class="cc_paginator_legend">
                            {{pageLabelMap 'PaginatorItems'}} {{startItem}} - {{endItem}} {{pageLabelMap 'PaginatorOf'}} {{totalRecords}} {{pageLabelMap 'PaginatorTotal'}}
                        </p>
                    </div>
                    <div class="col-xs-4">
                        <div class="text-center cc_current_page">
                            {{pageLabelMap 'PaginatorPage'}}
                            {{#if hasPrevious}}
                                <a href="#" class="firstAction cc_first_action">{{pageLabelMap 'PaginatorFirst'}}</a>
                                <a href="#" class="previousAction pageAction cc_page_action">{{pageLabelMap 'PaginatorPrevious'}}</a>
                            {{/if}}
                            {{#for startPage endPage 1}}
                                {{#ifEquals this ../currentPage}}
                                    {{safeQuote this}} 
                                {{else}} 
                                    <a href="#" class="gotoPage cc_goto_page" data-id="{{safeQuote this}}">{{safeQuote this}}</a>
                                {{/ifEquals}} 
                            {{/for}}
                            {{#if hasNext}}
                                <a href="#" class="nextAction pageAction cc_page_action">{{pageLabelMap 'PaginatorNext'}}</a>
                                <a href="#" class="lastAction cc_last_action">{{pageLabelMap 'PaginatorLast'}}</a> 
                            {{/if}}
                        </div>
                    </div>
                    <div class="col-xs-4">
                        <div class="form-inline cc_form-inline cc_paginator_form pull-right">
                            <label for="itemsPerPage" class="cc_items_per_page">
                                {{pageLabelMap 'PaginatorShow'}}
                                <select id="itemsPerPage" class="form-control input-sm sizeAction cc_size_action">
                                    {{#each this.itemsPerPagePLValues}}
                                        <option value="{{safeQuote this}}" {{#ifEquals ../pageSize this}} selected {{/ifEquals}}>{{safeQuote this}}</option>
                                    {{/each}}
                                </select>
                                {{pageLabelMap 'PaginatorPerPage'}}
                            </label>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </script>
</apex:component>
pagination.component
次に商品一覧のVisualforceページを実装します。
※1 ページネーションを利用する際に、CloudCrazePageableからの拡張が必要です。
※2 modeは「server」「client」「infinite」がありますが、今回は「client」を指定します。
※3 stateはすべてのページネーション状態を格納するコンテナオブジェクトです。「firstPage」と「pageSize」プロパティーはそれぞれ、1と10を設定します。
※4 リモートアクションでコントローラーの「searchProduct」メソッドを呼び出し、商品一覧レコードを取得します。
<apex:page docType="html-5.0" sidebar="false" showHeader="false" standardStylesheets="false" applyHtmlTag="false" controller="ProductListCtrl">
     <c:pagination eLName=".paginator"/>

    <div class="paginator"></div>
    <div class="productList"></div>

    <script type="text/javascript">
        jQuery(function($) {
            var productListCollection = CCRZ.CloudCrazePageable.extend({ //※1
                mode: 'client',  //※2
                silent: false,
                state: {  //※3
                    firstPage: 1,
                    pageSize: 10
                },
                className: 'ProductListCtrl',
                fetchAllNavData: function (state, formdata, callback) {
                    this.invokeCtx('searchProduct', function (res) {  //※4
                        callback(res.data);
                    }, { buffer: false, nmsp: false });
                }
            });
            var productlistView = CCRZ.CloudCrazeView.extend({
                templateDesktop: CCRZ.util.template('productListTmpl'),
                init: function () {
                    var v = this;
                    v.coll = new productListCollection();

                    var paginationView = new CCRZ.views.paginationView({
                        model: v.coll
                    });

                    this.listenTo(v.coll, 'reset', this.ready);
                    
                    paginationView.listenTo(
                        v.coll,
                        'pagination:host:rendered',
                        paginationView.hostRendered
                    );

                    this.generateDisplay(v.coll, function () {
                        v.render();
                    });
                },
                generateDisplay: function (coll, callback) {
                    coll.fetch({
                        success: function () {
                            if (_.isFunction(callback)) {
                                callback();
                            }
                        }
                    });
                },
                ready: function (dataList, args) {
                    this.coll = dataList;
                    this.render();
                },
                render: function () {
                    var v = this;
                    v.setElement('.productList');
                    v.$el.html(v.templateDesktop(v.coll.toJSON()));
                }
            });
            new productlistView();
        });
    </script>

    <script id="productListTmpl" type="text/template">
        <table class="table table-striped">
            <tr>
                <th>SKU</th>
                <th>名前</th>
                <th>開始日</th>
                <th>終了日</th>
                <th>商品種別</th>
                <th>ステータス</th>
                <th>商品インデックス状況</th>
            </tr>
            {{#each this}}
            <tr>
                <td>{{ccrz__SKU__c}}</td>
                <td>{{Name}}</td>
                <td>{{date ccrz__StartDate__c}}</td>
                <td>{{date ccrz__EndDate__c}}</td>
                <td>{{ccrz__ProductType__c}}</td>
                <td>{{ccrz__ProductStatus__c}}</td>
                <td>{{ccrz__ProductIndexStatus__c}}</td>
            </tr>
            {{/each}}
        </table>
    </script>
</apex:page>
productList.page

結果

もしナビゲーションのスタイルを変更したいという場合には、Bootstrapのpaginationを参考にしていただければ、ナビゲーションのスタイルも変えられると思います。

おわりに

ライブラリを使わずに、標準ページネーションとテンプレートを利用することで、ページネーションを作りましたが、いかがでしょうか。みなさんのB2B Commerceカスタマイズ開発に、お役に立てれば幸いです。
最後まで読んでいただきましてありがとうござした。
18 件
     
  • banner
  • banner

関連する記事