Pages

Showing posts with label Apex Method Imperatively. Show all posts
Showing posts with label Apex Method Imperatively. Show all posts

Monday, April 29, 2019

LWC : Calling Apex Method, Pagination, Fetching Child Records and Use of Child Templates


Hello guys, I am back with some new features of LWC. In this blog I will be covering the major features of LWC which we use on daily basis when we are coding with Visualforce or Aura components.

In this blog I will be explaining how to display list of Accounts with Pagination and also I will be explaining how to display child records like Contacts related to respective Account. I will also explain how we can do insert operation on Account object.

Let us start developing with lightning speed.

First we will be creating a controller class.

AccountController
1:  public class AccountController {  
2:       @AuraEnabled(cacheable=true)  
3:    public static PagedResult getAccountList(Integer pageNumber) {  
4:      Integer pageSize = 3;  
5:      Integer offset = (pageNumber - 1) * pageSize;  
6:      PagedResult result = new PagedResult();  
7:      result.pageSize = pageSize;  
8:      result.pageNumber = pageNumber;  
9:      result.totalItemCount = Database.countQuery('SELECT count() from Account');  
10:      result.records = Database.query('SELECT Id, Name, AccountNumber, Phone, '+  
11:                  '(Select Id,Name from Contacts) contacts FROM Account' +   
12:                  ' ORDER BY Name LIMIT :pageSize OFFSET :offset');  
13:      return result;  
14:    }  
15:    @AuraEnabled(cacheable=true)  
16:    public static List<Contact> getContactRecords(String accId){  
17:      return [Select Id,Name from Contact where AccountId =: accId];  
18:    }  
19:  }  

In the above code you guys must have noticed that I have used a wrapper class as 'PagedResult'. This wrapper class is used to hold list of Account records and pageNumber, pageSize etc.

'PagedResult' Wrapper class
1:  public class PagedResult {  
2:    @AuraEnabled  
3:    public Integer pageSize { get;set; }  
4:    @AuraEnabled  
5:    public Integer pageNumber { get;set; }  
6:    @AuraEnabled  
7:    public Integer totalItemCount { get;set; }  
8:    @AuraEnabled  
9:    public Object[] records { get;set; }  
10:  }  


Next, we will be creating LWC component to display list of Account records and pagination.

accountList.html
1:  <template>  
2:    <lightning-card title="Account List" icon-name="custom:custom63">  
3:      <div class="slds-m-around_medium">  
4:        <template if:true={listMode}>  
5:          <template if:true={accounts.data}>  
6:            <table border="1">  
7:              <thead>  
8:                <tr>  
9:                  <th>  
10:                    Name  
11:                  </th>  
12:                  <th>  
13:                    Number  
14:                  </th>  
15:                  <th>  
16:                    Phone  
17:                  </th>  
18:                  <th>  
19:                    Number of Contacts  
20:                  </th>  
21:                </tr>  
22:              </thead>  
23:              <tbody>  
24:                <template for:each={accounts.data.records} for:item="acc">  
25:                  <tr key={acc.Id}>  
26:                    <td>{acc.Name}</td>  
27:                    <td>{acc.AccountNumber}</td>  
28:                    <td>{acc.Phone}</td>  
29:                    <td>  
30:                      <c-numbercontactslink accountobj={acc} data-id={acc.Id} onclick={getAllContacts}></c-numbercontactslink>  
31:                      <!-- lightning-button variant="base" label={acc.Contacts.length} title="Number of Contacts" data-id={acc.Id} onclick={getAllContacts}></lightning-button -->  
32:                    </td>  
33:                  </tr>  
34:                </template>  
35:              </tbody>  
36:            </table>  
37:            <c-pagination page-number={pageNumber} page-size={accounts.data.pageSize} total-item-count={accounts.data.totalItemCount}  
38:            onprevious={handlePreviousPage} onnext={handleNextPage}></c-pagination>  
39:            <lightning-button label="Create Account" title="Create Account Record" onclick={createAccount}></lightning-button>  
40:          </template>  
41:        </template>  
42:        <template if:true={createMode}>  
43:            <lightning-input label="Id" disabled value={accountId}></lightning-input>  
44:            <lightning-input label="Name" onchange={handleNameChange} class="slds-m-bottom_x-small"></lightning-input>  
45:            <lightning-button label="Save Record" variant="brand" onclick={saveAccount}></lightning-button>  
46:            <lightning-button label="Cancel Record" variant="brand" onclick={cancelAccount}></lightning-button>  
47:        </template>  
48:        <template if:true={showContacts}>  
49:          <lightning-card title="Related Contact List" icon-name="custom:custom63">  
50:          <table>  
51:              <thead>  
52:                <tr>  
53:                  <th>  
54:                    Name  
55:                  </th>  
56:                </tr>  
57:              </thead>  
58:              <tbody>  
59:                <template for:each={contacts} for:item="con">  
60:                  <tr key={con.Id}>  
61:                    <td>{con.Name}</td>  
62:                  </tr>  
63:                </template>  
64:              </tbody>  
65:            </table>  
66:          </lightning-card>  
67:        </template>  
68:      </div>  
69:    </lightning-card>  
70:  </template>  


accountList.js
1:  import { LightningElement, wire, track} from 'lwc';  
2:  import { createRecord } from 'lightning/uiRecordApi';  
3:  import { ShowToastEvent } from 'lightning/platformShowToastEvent';  
4:  import { refreshApex } from '@salesforce/apex';  
5:  import ACCOUNT_OBJECT from '@salesforce/schema/Account';  
6:  import NAME_FIELD from '@salesforce/schema/Account.Name';  
7:  import ACCNUMBER_FIELD from '@salesforce/schema/Account.AccountNumber';  
8:  import getAccountList from '@salesforce/apex/AccountController.getAccountList';  
9:  import getContactRecords from '@salesforce/apex/AccountController.getContactRecords';  
10:  const CONTACT_FIELDS = [  
11:    'Contact.Name',  
12:    'Contact.Title',  
13:    'Contact.Phone',  
14:    'Contact.Email',  
15:  ];  
16:  export default class AccountListFunctionality extends LightningElement {  
17:    /** Current page in the account list. */  
18:    @track pageNumber = 1;  
19:    /** The number of items on a page. */  
20:    @track pageSize;  
21:    /** The total number of items matching the selection. */  
22:    @track totalItemCount = 0;  
23:    @wire(getAccountList, { pageNumber: '$pageNumber' })  
24:    accounts;  
25:    @track mode = 'list';  
26:    @track showContacts = false;  
27:    @track contacts;  
28:    createAccount(){  
29:      this.mode = 'create';  
30:    }  
31:    cancelAccount(){  
32:      this.mode = 'list';  
33:    }  
34:    handleNameChange(event) {  
35:      this.accountId = undefined;  
36:      this.name = event.target.value;  
37:      this.accnumber = event.target.value;  
38:    }  
39:    get listString() {  
40:      return JSON.stringify(this.accounts);  
41:    }  
42:    saveAccount() {  
43:      const fields = {};  
44:      fields[NAME_FIELD.fieldApiName] = this.name;  
45:      fields[ACCNUMBER_FIELD.fieldApiName] = this.accnumber;  
46:      const recordInput = { apiName: ACCOUNT_OBJECT.objectApiName, fields };  
47:      createRecord(recordInput)  
48:        .then(account => {  
49:          this.accountId = account.id;  
50:          this.mode = 'list';  
51:          this.dispatchEvent(  
52:            new ShowToastEvent({  
53:              title: 'Success',  
54:              message: 'Account created',  
55:              variant: 'success',  
56:            }),  
57:          );  
58:        }).then(() => {  
59:          return refreshApex(this.accounts);  
60:        })  
61:        .catch(error => {  
62:          this.dispatchEvent(  
63:            new ShowToastEvent({  
64:              title: 'Error creating record',  
65:              message: error.message,  
66:              variant: 'error',  
67:            }),  
68:          );  
69:        });  
70:    }  
71:    get listMode(){  
72:      if(this.mode === 'list'){  
73:        return true;  
74:      }  
75:      return false;  
76:    }  
77:    get createMode(){  
78:      if(this.mode === 'create'){  
79:        return true;  
80:      }  
81:      return false;  
82:    }  
83:    handlePreviousPage() {  
84:      this.pageNumber = this.pageNumber - 1;  
85:    }  
86:    handleNextPage() {  
87:      this.pageNumber = this.pageNumber + 1;  
88:    }  
89:    getAllContacts(event){  
90:      this.showContacts = true;  
91:      let accId = event.target.getAttribute('data-id');  
92:      console.log('acc id ==== ' + accId);  
93:      getContactRecords({accId})  
94:        .then(result => {  
95:          this.contacts = result;  
96:        })  
97:        .catch(error => {  
98:          this.error = error;  
99:        });  
100:    }   
101:  }  

'pagination.html' LWC Component
1:  <template>  
2:    <lightning-layout vertical-align="center" class="slds-m-horizontal_x-small">  
3:      <lightning-layout-item size="2">  
4:        <template if:false={isFirstPage}>  
5:          <lightning-button-icon icon-name="utility:chevronleft" onclick={handlePrevious}></lightning-button-icon>  
6:        </template>    
7:      </lightning-layout-item>  
8:      <lightning-layout-item size="8" class="nav-info">  
9:        {totalItemCount} items • page {currentPageNumber} of {totalPages}  
10:      </lightning-layout-item>  
11:      <lightning-layout-item size="2" class="nav-next">  
12:        <template if:false={isLastPage}>  
13:          <lightning-button-icon icon-name="utility:chevronright" onclick={handleNext}></lightning-button-icon>  
14:        </template>  
15:      </lightning-layout-item>  
16:    </lightning-layout>  
17:  </template>  

'pagination.js'
1:  import { LightningElement, api } from 'lwc';  
2:  export default class Paginator extends LightningElement {  
3:    /** The current page number. */  
4:    @api pageNumber;  
5:    /** The number of items on a page. */  
6:    @api pageSize;  
7:    /** The total number of items in the list. */  
8:    @api totalItemCount;  
9:    handlePrevious() {  
10:      this.dispatchEvent(new CustomEvent('previous'));  
11:    }  
12:    handleNext() {  
13:      this.dispatchEvent(new CustomEvent('next'));  
14:    }  
15:    get currentPageNumber() {  
16:      return this.totalItemCount === 0 ? 0 : this.pageNumber;  
17:    }  
18:    get isFirstPage() {  
19:      return this.pageNumber === 1;  
20:    }  
21:    get isLastPage() {  
22:      return this.pageNumber >= this.totalPages;  
23:    }  
24:    get totalPages() {  
25:      return Math.ceil(this.totalItemCount / this.pageSize);  
26:    }  
27:  }  

'numberconatctslink.html' LWC Component
1:  <template>  
2:      <lightning-button variant="base" label={labelName} title="Number of Contacts"></lightning-button>  
3:    </template>  

numbercontactslink.js
1:  import { LightningElement, track, api } from 'lwc';  
2:  export default class Numbercontactslink extends LightningElement {  
3:    @api labelName;  
4:    @api accountRec;  
5:    @api  
6:    get accountobj() {  
7:      return this.accountRec;  
8:    }  
9:    set accountobj(value){  
10:      this.accountRec = value;  
11:      if(this.accountRec.Contacts != undefined){  
12:        this.labelName = this.accountRec.Contacts.length;  
13:      }else{  
14:        this.labelName = 0;  
15:      }  
16:    }  
17:  }  

Working Demo: