Wednesday, September 28, 2022

LWC Datatable with Pagination and keep selected rows persistent

 Here is the code to display data in LWC Datatable with pagination and keep selected rows persistent between each page.


accountsTable.html :

<template>
  <lightning-card
    variant="Narrow"
    title="Partner Lookup"
    icon-name="standard:contact"
    class="slds-var-m-around_small"
  >
    <lightning-button
      variant="brand"
      icon-name="utility:email"
      label="Send Email"
      title="Brand action"
      slot="actions"
      onclick={openEmailPopup}
      disabled={disableEmail}
    >
    </lightning-button>
    <div class="slds-card__body slds-card__body_inner">
      <template if:true={showLoading}>
        <lightning-spinner
          alternative-text="Loading"
          size="medium"
          class="spinnerClass"
          variant="brand"
        >
        </lightning-spinner>
      </template>
      <lightning-input
        type="search"
        class="slds-size_4-of-12 slds-var-p-bottom_small"
        label="Company"
        value={searchKey}
        onchange={handleSearchChange}
      >
      </lightning-input>
      <template if:false={noData}>
        <lightning-datatable
          data-id="table"
          key-field="Id"
          data={data}
          columns={columns}
          onrowselection={onRowSelection}
          selected-rows={allSelectedRows}
          class="slds-table_bordered"
        >
        </lightning-datatable>
        <div slot="footer">
          <lightning-layout class="slds-var-p-around_small">
            <lightning-layout-item class="slds-size_2-of-12">
              <lightning-button
                label="Previous"
                icon-name="utility:chevronleft"
                onclick={previousHandler}
                disabled={disbalePrevious}
              >
              </lightning-button>
            </lightning-layout-item>
            <lightning-layout-item class="slds-size_2-of-12">
              Page {page} of {totalPage}
            </lightning-layout-item>
            <lightning-layout-item class="slds-size_2-of-12">
              <lightning-button
                label="Next"
                icon-name="utility:chevronright"
                icon-position="right"
                onclick={nextHandler}
                disabled={disbaleNext}
              >
              </lightning-button>
            </lightning-layout-item>
          </lightning-layout>
        </div>
      </template>
      <template if:true={noData}>
        <p class="slds-text-heading_small slds-var-p-top_small">
          No matching Accounts to display.
        </p>
      </template>
    </div>
  </lightning-card>
  <template if:true={showModal}>
    <section aria-modal="true" class="slds-modal slds-fade-in-open">
      <div class="slds-modal__container">
        <header class="slds-modal__header">
          <h2 class="slds-text-heading_small">Send Email</h2>
          <lightning-button-icon
            class="slds-modal__close"
            icon-name="utility:close"
            variant="bare-inverse"
            onclick={closeModal}
            alternative-text="Close"
            title="Close"
          >
          </lightning-button-icon>
        </header>
        <div
          class="slds-var-p-around_small slds-modal__content modalBody slds-is-relative"
        >
          <template if:true={showModelLoading}>
            <lightning-spinner
              alternative-text="Loading"
              size="medium"
              class="spinnerClass"
              variant="brand"
            >
            </lightning-spinner>
          </template>
          <lightning-layout multiple-rows="true" horizontal-align="space">
            <lightning-layout-item size="12">
              <lightning-input
                name="recipients"
                required="true"
                value={recipients}
                label="Recipients"
                onchange={onChangeRecipient}
              >
              </lightning-input>
            </lightning-layout-item>
            <lightning-layout-item size="12">
              <lightning-combobox
                name="template"
                label="Template"
                value={selectedTemplate}
                placeholder="Select Template"
                options={templateOptions}
                onchange={handleTemplateChange}
              >
              </lightning-combobox>
            </lightning-layout-item>
            <lightning-layout-item size="12">
              <lightning-input
                name="subject"
                required="true"
                value={subject}
                label="Subject"
                onchange={onChangeSubject}
              >
              </lightning-input>
            </lightning-layout-item>
            <lightning-layout-item size="12">
              <lightning-input-rich-text
                value={htmlBody}
                label="Content"
                label-visible="true"
                share-with-entity-id={recordId}
                required="true"
                onchange={onChangeContent}
              >
              </lightning-input-rich-text>
            </lightning-layout-item>
          </lightning-layout>
        </div>
        <footer class="slds-modal__footer">
          <lightning-button
            variant="neutral"
            label="Cancel"
            title="Cancel"
            onclick={closeModal}
            class="slds-var-p-right_small"
          >
          </lightning-button>
          <lightning-button
            variant="brand"
            icon-name="utility:send"
            label="Send"
            title="Send"
            onclick={onClickSendEmail}
          >
          </lightning-button>
        </footer>
      </div>
    </section>
    <div class="slds-backdrop slds-backdrop_open"></div>
  </template>
</template>


AccountsTable.js:


import { LightningElement, wire, api, track } from "lwc";
import getPartners from "@salesforce/apex/AccountController.getPartners";
import getRecipients from "@salesforce/apex/AccountController.getRecipients";
import getEmailBody from "@salesforce/apex/AccountController.getEmailBody";
import sendEmail from "@salesforce/apex/AccountController.sendEmail";
import emailTemplateLabel from "@salesforce/label/c.AccountTemplates";
import { ShowToastEvent } from "lightning/platformShowToastEvent";

const columns = [
  { label: "First Name", fieldName: "FirstName", type: "text" },
  { label: "Last Name", fieldName: "LastName", type: "text" },
  { label: "Email", fieldName: "Email", type: "text" },
  { label: "Phone", fieldName: "Phone", type: "Text" },
  { label: "Country", fieldName: "MailingCountry", type: "Text" }
];
const DELAY = 300;
export default class AccountsTable extends LightningElement {
  @api recordId = null;
  @track showLoading = true;
  @track showModelLoading = true;
  @track searchKey = "";
  @track page = 1;
  @track items = [];
  @track data = [];
  @track columns;
  @track startingRecord = 1;
  @track endingRecord = 0;
  @track pageSize = 10;
  @track totalRecountCount = 0;
  @track totalPage = 0;
  @track disableEmail = true;
  @track allSelectedRows = [];
  @track error;
  @track showModal = false;
  @track recipients;
  @track selectedrecipients;
  @track selectedTemplate;
  @track subject;
  @track htmlBody;
  isPageChanged = false;
  initialLoad = true;

  @wire(getPartners, {
    recId: "$recordId",
    searchKey: "$searchKey"
  })
  wiredPartners({ error, data }) {
    if (data) {
      this.processRecords(data);
      this.error = undefined;
      this.showLoading = false;
    } else if (error) {
      this.error = error;
      this.data = undefined;
      this.showLoading = false;
    }
  }
  processRecords(data) {
    this.items = data;
    this.totalRecountCount = data.length;
    this.totalPage = Math.ceil(this.totalRecountCount / this.pageSize);
    const arr = this.items.slice(0, this.pageSize);
    const newArr = arr.map((object) => {
      return { ...object, Id: object.Id + "-1" };
    });
    this.data = newArr;
    this.endingRecord = this.pageSize;
    this.columns = columns;
  }
  get disbalePrevious() {
    return this.page == 1;
  }
  get disbaleNext() {
    return this.page == this.totalPage;
  }
  previousHandler() {
    this.showLoading = true;
    this.isPageChanged = true;
    if (this.page > 1) {
      this.page = this.page - 1;
      this.displayRecordPerPage(this.page);
    }
    this.showLoading = false;
  }
  nextHandler() {
    this.showLoading = true;
    this.isPageChanged = true;
    if (this.page < this.totalPage && this.page !== this.totalPage) {
      this.page = this.page + 1;
      this.displayRecordPerPage(this.page);
    }
    this.showLoading = false;
  }
  displayRecordPerPage(page) {
    this.startingRecord = (page - 1) * this.pageSize;
    this.endingRecord = this.pageSize * page;
    this.endingRecord =
      this.endingRecord > this.totalRecountCount
        ? this.totalRecountCount
        : this.endingRecord;
    const arr = this.items.slice(this.startingRecord, this.endingRecord);
    const newArr = arr.map((object) => {
      return { ...object, Id: object.Id + "-" + page };
    });
    this.data = newArr;
    this.startingRecord = this.startingRecord + 1;
    this.template.querySelector(
      '[data-id="table"]'
    ).selectedRows = this.allSelectedRows;
  }
  onRowSelection(event) {
    if (!this.isPageChanged || this.initialLoad) {
      this.initialLoad = false;
      var selectedRows = event.target.selectedRows;
      var allSelectedRows = this.allSelectedRows;
      var currentPageNumber = this.page;
      //Process the rows now
      //Condition 1 -> If any new row selected, add to our allSelectedRows attribute
      //Condition 2 -> If any row is deselected, remove from allSelectedRows attribute
      //Solution - Remove all rows from current page from allSelectedRows attribute and then add again
      //Removing all rows coming from curent page from allSelectedRows
      var i = allSelectedRows.length;
      if (i > 0) {
        while (i--) {
          var pageNumber = allSelectedRows[i].split("-")[1];
          if (pageNumber && pageNumber == currentPageNumber) {
            allSelectedRows.splice(i, 1);
          }
        }
      }
      selectedRows.forEach(function (row) {
        allSelectedRows.push(row);
      });
      if (allSelectedRows.length > 0) {
        this.disableEmail = false;
      } else {
        this.disableEmail = true;
      }
      this.allSelectedRows = allSelectedRows;
    } else {
      this.isPageChanged = false;
    }
  }
  handleSearchChange(event) {
    this.showLoading = true;
    window.clearTimeout(this.delayTimeout);
    const searchKey = event.target.value;
    this.delayTimeout = setTimeout(() => {
      this.searchKey = searchKey;
      var data = [];
      for (var i = 0; i < this.items.length; i++) {
        if (
          this.items[i] != undefined &&
          this.items[i].FirstName.includes(this.searchKey)
        ) {
          data.push(this.items[i]);
        }
      }
      this.processRecords(data);
      this.page = 1;
      this.showLoading = false;
    }, DELAY);
  }
  openEmailPopup() {
    this.showModal = true;
    this.showModelLoading = true;
    var recs = [];
    for (var i = 0; i < this.allSelectedRows.length; i++) {
      recs.push(this.allSelectedRows[i].split("-")[0]);
    }
    getRecipients({ recIds: recs })
      .then((result) => {
        this.showModelLoading = false;
        this.recipients = result;
        this.selectedrecipients = result;
        this.error = undefined;
      })
      .catch((error) => {
        this.showModelLoading = false;
        this.recipients = undefined;
        this.selectedrecipients = undefined;
        this.error = error;
      });
  }
  get templateOptions() {
    var options = emailTemplateLabel.split(";");
    var resultMap = [];
    for (let i = 0; i < options.length; i++) {
      resultMap.push({
        class: "optionClass",
        label: options[i],
        value: options[i]
      });
    }
    return resultMap;
  }
  onChangeRecipient(event) {
    this.recipients = event.detail.value;
  }
  onChangeSubject(event) {
    this.subject = event.detail.value;
  }
  onChangeContent(event) {
    this.htmlBody = event.detail.value;
  }
  handleTemplateChange(event) {
    this.showModelLoading = true;
    this.selectedTemplate = event.detail.value;
    getEmailBody({ leadId: this.recordId, templateName: this.selectedTemplate })
      .then((result) => {
        this.showModelLoading = false;
        for (var key in result) {
          this.subject = key;
          this.htmlBody = result[key];
        }
        this.error = undefined;
      })
      .catch((error) => {
        this.showModelLoading = false;
        this.error = error;
        this.subject = undefined;
        this.htmlBody = undefined;
      });
  }
  get noData() {
    return this.items.length == 0 ? true : false;
  }
  closeModal() {
    this.closeEmailModel();
  }
  onClickSendEmail() {
    if (
      this.recipients == undefined ||
      this.recipients == null ||
      this.recipients == ""
    ) {
      this.showToast("error", "Error", "Enter the Recipients");
    } else if (
      this.subject == undefined ||
      this.subject == null ||
      this.subject == ""
    ) {
      this.showToast("error", "Error", "Enter the Subject");
    } else if (
      this.htmlBody == undefined ||
      this.htmlBody == null ||
      this.htmlBody == ""
    ) {
      this.showToast("error", "Error", "Enter the Content");
    } else {
      this.showModelLoading = true;
      sendEmail({
        leadId: this.recordId,
        toAddress: this.recipients,
        subject: this.subject,
        body: this.htmlBody
      })
        .then((result) => {
          this.showToast("success", "Success!", "Email sent successfully.");
          this.error = undefined;
          this.closeEmailModel();
        })
        .catch((error) => {
          this.showModelLoading = false;
          this.error = error;
          this.showToast("error", "Email sending failed!", this.error);
        });
    }
  }
  closeEmailModel() {
    this.recipients = this.selectedrecipients;
    this.selectedTemplate = undefined;
    this.subject = undefined;
    this.htmlBody = undefined;
    this.showModelLoading = false;
    this.showModal = false;
  }
  showToast(type, title, msg) {
    const evt = new ShowToastEvent({
      title: title,
      message: msg,
      variant: type,
      mode: "dismissable"
    });
    this.dispatchEvent(evt);
  }
}

AccountController.apxc

public class AccountController { @AuraEnabled(cacheable=true) public static List<partnerData> getPartners(String recId, String searchKey){ String partnerName; if(String.isNotBlank(searchKey)){ partnerName = searchKey+'%'; } List<partnerData> partnerList = new List<partnerData>(); for(Contact con : [SELECT Id,FirstName,LastName,Email,Phone,MailingCountry From Contact where FirstName like:partnerName]){ partnerList.add(new partnerData(con)); } return partnerList; } @AuraEnabled public static String getRecipients(List<String> recIds){ Set<String> recSet = new Set<String>(); for(Contact con :
                [SELECT Id,FirstName,LastName,Email,Phone,MailingCountry From Contact Where Id IN:recIds order by Name]){ recSet.add(con.Email); } return String.join(new List<String>(recSet),';'); } @AuraEnabled public static map<string,string> getEmailBody(String leadId, String templateName){ map<string,string> emailmap = new map<string,string>(); EmailTemplate et = [select id,Name,Subject,Body from EmailTemplate where Name=:templateName]; Messaging.SingleEmailMessage email = Messaging.renderStoredEmailTemplate(et.id, leadId ,null); if(email.getHtmlBody() != null ){ emailmap.put(email.getSubject(),email.getHtmlBody()); }else{ emailmap.put(email.getSubject(),email.getPlainTextBody()); } return emailmap; } @AuraEnabled public static String sendEmail(String leadId,String toAddress,String subject,String body){ List<Messaging.SingleEmailMessage> mails = new List<Messaging.SingleEmailMessage>(); Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); mail.setToAddresses(toAddress.split(';')); mail.setTargetObjectId(leadId); // mail.setReplyTo('noreply@gmail.com'); // change it with your mail address. // mail.setSenderDisplayName('salesforce User'); mail.setSubject(subject); mail.setHtmlBody(body); mail.setTreatTargetObjectAsRecipient(false); mail.setSaveAsActivity(true); mails.add(mail); try{ Messaging.sendEmail(mails); return 'Success'; }catch(exception e){ return e.getMessage(); } } public class partnerData{ @AuraEnabled public string Id{get;set;} @AuraEnabled public string FirstName{get;set;} @AuraEnabled public string LastName{get;set;} @AuraEnabled public string Email{get;set;} @AuraEnabled public string Phone{get;set;} @AuraEnabled public string MailingCountry{get;set;} public partnerData(Contactpartner){ this.Id = partner.Id; this.FirstName       = partner.FirstName; this.LastName        = partner.LastName; this.Email           = partner.Email; this.Phone          = partner.Phone; this.MailingCountry  = partner.MailingCountry ; } } }

No comments:

Post a Comment