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
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
Next, we will be creating LWC component to display list of Account records and pagination.
accountList.html
accountList.js
'pagination.html' LWC Component
'pagination.js'
'numberconatctslink.html' LWC Component
numbercontactslink.js
Working Demo:
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: