Lightning Web Components(LWC)へようこそ : Cached Recordを利用したページング

January 6, 2019 Pankaj Mehra



こんにちは。今回は先日発表されたばかりのLightning Web Components(LWC)を使ったページングとキャッシュ機能のあるリストビューのサンプルプログラムをご紹介したいと思います。


Winter’19のプレリリースの際に、Lightning Web Components(LWC)が初めて紹介されました。Lightning Components を作成する際には、従来のプログラミングモデルであるAura Components と、新しいプログラミングモデルであるLWCの両方が使用できるようになります。LWCは、1つのページ上でAura Componentsと共存して同時に使用することができます。それはパッと見たところではNode.jsやReactのプログラミング言語と似ていますがコードはそれらよりも習得しやすいです。はじめるためにNode.jsとReactに慣れている必要はありません。単純にTrailheadとドキュメントを参照するだけで十分です。SF標準の開発コンソールはまだサポートされていませんがVS codeがあればSalesforce DXと共に十分に取り組んでいただけると思います。

  • セールスフォース developers の「Introducing Lightning Web Components」へのリンクはこちらです。
  • セールスフォース developers の「Playground」 へのリンクはこちらです。
    私はまだ試していませんが、小さいコンポーネント群を使いながらいろいろ試すにはおすすめです。


では早速LWCのデモをはじめましょう!これからページングとキャッシュ機能のある簡単なリストビューを作ってみたいと思います。

Lightning Web Components は  SFDX を使っているため、まずはSFDXセットアップを行いましょう。

インストール情報 :
SFDX CLIツールのダウンロードリンク
macOS : https://sfdc.co/sfdx_cli_osx
Windows 32-bit : https://sfdc.co/sfdx_cli_win
Windows 64-bit : https://sfdc.co/sfdx_cli_win64

インストール手順  :
ターミナルにて > sfdx plugins
Pluginのインストール> sfdx plugins:install salesforcedx@pre-release

Visual Studio Code:

  1. Visual Studio Codeのインストール
  2. Visual Studio Code用Salesforce Extension Pack [From Salesforce]のインストール
  3. Visual Studio Code用Lightning Web Components [From Salesforce]のインストール

新しい LWC Projectを作成:

  1. Visual Studio codeにて MacならCommand + Shift + P、WindowsならCtrl + Shift + P を押下します。
  2. SFDXと入力, SFDX: Create Projectを選択します。
  3. Project名としてPaginationLigtningWebComponentを入力します。[Project保存用フォルダーも指定します。].
  4. Create Projectを押下します.。
  5. Dev Hubを認証するため,   SFDX: Authorize a Dev Hub のコマンドを入力します。
  6. 引き続きScratch Orgを作成するため, SFDX: Create a Default Scratch Org のコマンドを入力します。
  7. 提示されるデフォルトのJSONファイルを選択し、Project名を入力します。Scratch Orgの寿命(有効期限)を 7日に指定します。
  8. SFDX: Open Default Org, を入力しログインできるか確認します。もしログインに失敗した場合はscratch orgに紐づいているDev Hub組織のログインユーザーemailアドレスを確認し、以下のコマンドを入力し手動でパスワードを再生成します。
    • sfdx force:user:password:generate --targetusername [USERNAME-UNDER-ACTIVE-SCRATCH-ORG]
    • 上記のコマンドは全てCLIコマンドです。

Salesforce DXのセットアップが完了したら、Lighting web componentが作成できるようになります。Salesforce DXのセットアップでエラーが発生し解決できない場合、その解決に役立つ沢山のドキュメントがありますし、私のほうでも個別にヘルプさせていただきます。
 

続いて、Lightning Web Componentを作成します。

  1. コマンドを入力します。> SFDX: Create Lightning Web Component. エンターキーを押し デフォルトの force-app/main/default/lwc を指定します。
  2. 新しいコンポーネントの名前としてpaginationlightningcomponentsを指定します。もしエラーが出た場合は Lightning Component bundle は親フォルダーである lightning コンポーネントに付属している必要があります。
  3. Project が正常に作成された場合、以下のような構成が確認できます。

デモについて:

これからページング機能を持ち、複数のレコードをリストビューで表示しているLightning Web component のデモを紹介します。リストビューはキャッシュされており、追加分のレコードは必要な場合のみサーバーから検索します。 一旦サーバーから検索したレコードはキャッシュに保持され必要に応じてページング処理に使われます。



ソースコードについて :

  1. Lightningcomponents.html :
    このLightning web componentファイルは既存のLightning componentと似ていますが、主な違いは属性の定義がコントローラーのjs(JavaScript)ファイルのほうに移っていることです。また、アノテーションのほうにも軽微な変更がありますが、もっとも目立つのはもauraアノテーション定義が完全になくなっていることです。尚、SLDS(SFDC lightning designing system)は今まで通りサポートされています。
    template>
           <lightning-card title="Pagination Demo" icon-name="custom:custom63">
               <div class="slds-m-around_medium">
                   <table class="slds-table slds-table_cell-buffer slds-table_bordered">
                       <thead>
                           <tr class="slds-line-height_reset">
                           <th class="slds-text-title_caps" scope="col">
                           <div class="slds-truncate" title="Contact Name">Contact Name</div>
                           </th>
                           <th class="slds-text-title_caps" scope="col">
                           <div class="slds-truncate" title="Account Name">Account Name</div>
                           </th>
                       
                           <th class="slds-text-title_caps" scope="col">
                           <div class="slds-truncate" title="Email">Email</div>
                           </th>
                           <th class="slds-text-title_caps" scope="col">
                           <div class="slds-truncate" title="Phone">Phone</div>
                           </th>
                           </tr>
                       </thead>
                       <template if:true={contacts}>
                              
                       <tbody>
                           <template for:each={contacts} for:item="contact">
                           <tr key={contact.Id} class="slds-hint-parent">
                           <th data-label="Opportunity Name" scope="row">
                           <div class="slds-truncate" title="Cloudhub">{contact.Name}</div>
                           </th>
                           <td data-label="Account Name">
                           <div class="slds-truncate" title="Cloudhub">{contact.Account.Name}</div>
                           </td>
                         
                           <td data-label="Confidence">
                           <div class="slds-truncate" title="20%">{contact.Email}</div>
                           </td>
                           <td data-label="Amount">
                           <div class="slds-truncate" title="$25k">{contact.Phone}</div>
                           </td>
                           </tr>
                           </template>
                         
                       </tbody>
                       </template>
                   </table>
                  
     
     
                   <!--ERROR Section-->
                   <template if:true={error}>
                       ERROR:{error}<br/>
                       <template if:true={error.details}>
                           {error.details}<br/>
                           <template if:true={error.details.body}>
                               {error.details.body}<br/>
                               <template if:true={error.details.body.message}>
                                   {error.details.body.message}<br/>
                               </template>
                           </template>
                       </template>
                      
                   </template>   
               </div>
     
               <lightning-layout>
                   <lightning-layout-item>
                       <lightning-button label="Previous" icon-name="utility:chevronleft" onclick={handlePrevious}></lightning-button>
                   </lightning-layout-item>
                   <lightning-layout-item flexibility="grow" style="text-align: center;">
                       Page :{pageNumber} of {totalPages} [Cached {currentRecordCount} records of total {count} Records]
                   </lightning-layout-item>
                   <lightning-layout-item>
                       <lightning-button label="Next" icon-name="utility:chevronright" icon-position="right" onclick={handleNext}></lightning-button>
                   </lightning-layout-item>
               </lightning-layout>
     
           </lightning-card>
     
    </template>
  2. Lightningcomponents.js :
    コンポーネントhtmlファイルに対応するコントローラーjs(JavaScript)になります。また、 import、export、extends、Apex クラスのStaticメソッドへの参照などApexコードでも見慣れているキーワードが再び登場しています。
    /* eslint-disable guard-for-in */
    re { LightningElement,track} from 'lwc';
    import getContactList from '@salesforce/apex/LWCContactDAO.getContactList';
    import getCount from '@salesforce/apex/LWCContactDAO.getContactCount';
     
    export default class Lightningcomponents extends LightningElement {
       @track contacts = [];
       allContacts = [];
       @track error;
       @track lastId = '';
       @track currentRecordCount = 0;
       @track pageNumber = 1;
       pageSize = 10;
       @track count;
       @track totalPages = 0;
     
       constructor() {
           super();
           getCount()
               .then(result => {
                   this.count = result;
                   this.totalPages = Math.ceil(this.count/this.pageSize);
               })
               .catch(error => {
                   this.error = error;
           });
           this.getContactListJs();
       }
     
       getContactListJs(){
           var i = 0;
           getContactList({ lastId: this.lastId })
               .then(result => {
                   for(i in result) {
                       this.allContacts.push(result[i]);
                   }
                   this.contacts = result;
                   this.currentRecordCount = result.length + this.currentRecordCount;
                   this.pageNumber = Math.ceil(this.allContacts.length / this.pageSize);
                   this.lastId = result.length === 0 ? '' :  result[result.length -1].Id;
               })
               .catch(error => {
                   this.error = error;
           });
       }
     
       handlePrevious() {
           var hasNext = this.pageNumber > 1;
           this.pageNumber = hasNext ? this.pageNumber - 1 : this.pageNumber;
           // Disable the prev button
           if(hasNext){
               this.prepparePage(false);
           }
       }
     
       handleNext() {
           var maxPage = Math.ceil(this.currentRecordCount/this.pageSize);
           if(maxPage === this.pageNumber && maxPage < this.totalPages) {
               this.getContactListJs();
           } else {
                // TODO: Disable the next button
                this.prepparePage(true);
           }
       }
     
       prepparePage(isNext){
           var startIndex = isNext ? this.pageNumber * this.pageSize : (this.pageNumber -1) * this.pageSize;
           var endIndex = isNext ? (this.pageNumber +1) * this.pageSize : this.pageNumber * this.pageSize ;
           var i = startIndex;
           this.contacts = [];
           for(i; i < endIndex ; i++){
               if(this.allContacts[i] != null){
                   this.contacts.push(this.allContacts[i]);
               }
           }
           this.pageNumber = isNext && this.pageNumber < this.pageSize? this.pageNumber + 1 : this.pageNumber;
       }
    }

     

  3. Lightningcomponents.js-meta.xml
    Apexファイル関連でも必要だったこのMetadataファイルはLWCではさらに別の情報を持っています。例えば、該当LWCをどのLightning Appタイプにデプロイさせるのかが定義できます。
    <?xml version="1.0" encoding="UTF-8"?>
    <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="lightningcomponents">
    <apiVersion>45.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
    <target>lightning__AppPage</target>
    <target>lightning__RecordPage</target>
    <target>lightning__HomePage</target
    </targets>
    </LightningComponentBundle>
  4. Apex class :
    最後は今回の用途だとデータを抽出し提供するサーバー側のクラスになります。オブジェクトからデータを抽出・処理するクールな様々な実装が可能ですが、例えばレコードページ間の画面遷移など基本的な制御はカスタムコード1行もなく対応できます。
    public class LWCContactDAO {
       @AuraEnabled(cacheable=true)
       public static List<Contact> getContactList(String lastId){
    return (lastId == null || lastId == '' ?
                  ([Select Id, Name, Account.Name, Email, LastName, FirstName, Phone
                  FROM Contact ORDER BY Id DESC limit 10]):
            	   ([Select Id, Name, Account.Name, Email, LastName, FirstName, Phone
                  FROM Contact Where Id < :lastId order by Id DESC limit 10]));
       }
      
       @AuraEnabled(cacheable=true)
       public static Integer getContactCount(){
           return [Select count() FROM Contact];
       }
    }

Tips : 

  1. ローカルにコード保存後は下記のコマンドを使いScratch orgにプッシュできます。
    SFDX: Push Source to Default Scratch Org
  2. 最初のセットアップ手順でScratch orgの寿命(有効期限)を7日に設定してあるため、完成したAppは下記のコマンドにてDev Hub orgに反映(デプロイ)することをお勧めします。
    sfdx force:mdapi:deploy -d PaginationLigtningWebComponent -u [USERNAME-UNDER-ACTIVE-SCRATCH-ORG]
    
    - sfdx force:auth:web:login -d -a spring19hub]にてログイン状態なら上記の全てのコマンドはターミナルのCLIだけで実行できます。
    - PaginationLigtningWebComponent はProjectフォルダー名です。

最後に


Lightning Web Component(LWC)はsalesforceアプリケーションを作成する時にパワーフルな手段になると思います。そこには沢山のクールなAPIが存在しそれらを使うことによりカスタムコードを減らし、またアプリケーションのパフォーマンスを向上させ、もっとレスポンシブでライトウエイトな開発体験・ユーザー体験を提供してくれると信じています

 

 
 

アピリオのリソースハブにもさまざまな資料を掲載しています。

 
戻る
Heroku Tips(4) Gitlabで自動デプロイ
Heroku Tips(4) Gitlabで自動デプロイ

Herokuで開発を行う際にコード管理とサーバーへのデプロイをどのように実施していますか?GitLab CI の仕組みを利用して、masterブランチへのコミット時に自動的にHerokuサーバーにデプロイすることも...

次へ
Heroku Tips (3) Papertrail を使いこなす
Heroku Tips (3) Papertrail を使いこなす

今回のTips 3 では Heroku アプリケーションを使う上でなくてはならないアドオンである Papertrail を取り上げてみたいと思います。

アピリオまでお気軽にお問合せください

ご質問はこちら