Pages

Showing posts with label Service Component. Show all posts
Showing posts with label Service Component. Show all posts

Sunday, May 24, 2020

Lightning Web Component : What are Service Components & How are they Useful?

As we keep working on complex LWC applications, it’s inevitable that complexity will increase. With increased complexity in code, we will need to write a modular reusable code. In this blog, I will try to explain how we can create a reusable LWC code using Service Components.

Let's try to define What is Service Components?

A service component is a component that provides a set of functionalities in a single component. Ideally, the service should be specialized, generic, and reusable. Also, this component does not have a markup, i.e. this is not visible by default.
This helps in reducing code duplication and simplifies the component's code. This, in turn, makes the code more robust and easier to maintain.

How we can Create a Service Component?

I have taken an Account object for my example and I will be creating a service component for my Account object.

AccountService.cls as Apex Class:

public with sharing class AccountService {
    
    public AccountService() {

    }

    @AuraEnabled
    public static List<Account> searchAccountByName(String accountName) {
        List<Account> accounts = [SELECT Id, Name FROM Account WHERE Name=:accountName];
        if (accounts.size() > 0) {
            return accounts;
        }
        return null;
    }

    @AuraEnabled
    public static List<Account> fetchAccountById(String accountId) {
        List<Account> accounts = [SELECT Id, Name FROM Account WHERE Id=:accountId];
        if (accounts.size() > 0) {
            return accounts;
        }
        return null;
    }

    @AuraEnabled
    public static List<Account> fetchAccountsByIds(List<Id> accountIds) {
        List<Account> accounts = [SELECT Id, Name FROM Account WHERE Id in: accountIds];
        if (accounts.size() > 0) {
            return accounts;
        }
        return null;
    }

    @AuraEnabled
    public static List<Account> searchAccounts(String accountName) {
        String query = 'Select Id, Name from Account where Name like ' + '\'%' + accountName + '%\'';
        List<Account> accounts = Database.query(query);
        if (accounts.size() > 0) {
            return accounts;
        }
        return null;
    }

    @AuraEnabled
    public static List<Account> fetchAllAccounts(List<Id> accountIds) {
        List<Account> accounts = [SELECT Id, Name FROM Account LIMIT 10];
        if (accounts.size() > 0) {
            return accounts;
        }
        return null;
    }
}


accountService as Service Component:

import getAccountByName from "@salesforce/apex/AccountService.searchAccountByName";
import getAccountById from "@salesforce/apex/AccountService.fetchAccountById";
import getAccountsByIds from "@salesforce/apex/AccountService.fetchAccountsByIds";
import getAccounts from "@salesforce/apex/AccountService.searchAccounts";
import getAllAccounts from "@salesforce/apex/AccountService.fetchAllAccounts";

const searchAccountByName = async accountName => {
   const response = await getAccountByName({ accountName: accountName });
   return response;
};

const searchAccountById = async accountId => {
    const response = await getAccountById({ accountId: accountId });
    return response;
};

const searchAccountsByIds = async accountIds => {
    const response = await getAccountsByIds({ accountIds: accountIds });
    return response;
};

const fetchAccounts = async accountName => {
    const response = await getAccounts({ accountName: accountName });
    return response;
 };

const fetchAllAccounts = () => {
   return new Promise(resolve => {
    getAllAccounts()
         .then(data => {
            resolve(data);
         })
         .catch(error => {
            resolve(error);
         });
   });
};

export { searchAccountByName, searchAccountById, searchAccountsByIds, fetchAccounts, fetchAllAccounts };

In the above component, I have exposed the below services

  • searchAccountByName: it accepts the search key as accountName and will return the account record with the exact account name
  • searchAccountById: it accepts the search key as accountId and will return the account with the exact account id
  • searchAccountsByIds: it accepts the set of account ids and will return the list of account
  • fetchAccounts: it accepts the search key as accountName and will return the list of Account records which contains name as search keyword.
  • fetchAllAccounts: this returns the list of accounts.
You will also notice that I have followed the Singleton pattern to develop this component i.e. this component has only one instance.
Now to use the above services, I have created one component which will consume these services.

accountInfo as LWC Component:

accountInfoComponent.html

<template>
        <lightning-button label="Get All Accounts" onclick={handleClick}></lightning-button>
      
        <lightning-layout vertical-align="end" class="slds-m-bottom_small">
            <lightning-layout-item flexibility="grow">
                <lightning-input type="search" onchange={handleKeyChange} label="Search By Exact Name" value={searchKey} ></lightning-input>
            </lightning-layout-item>
            <lightning-layout-item class="slds-p-left_xx-small">
                <lightning-button label="Search By Exact Name" onclick={handleSearchAccountByName}></lightning-button>
            </lightning-layout-item>
        </lightning-layout>

        <lightning-layout vertical-align="end" class="slds-m-bottom_small">
            <lightning-layout-item flexibility="grow">
                <lightning-input type="search" onchange ={handleKeyTextChange} label="Filter By Name" value={searchKeyText} ></lightning-input>
            </lightning-layout-item>
            <lightning-layout-item class="slds-p-left_xx-small">
                <lightning-button label="Filter By Name" onclick={handleSearchAccountsByName}></lightning-button>
            </lightning-layout-item>
        </lightning-layout>

        
            <lightning-card title="Account Result Data" icon-name="custom:custom3">
                <div class="slds-m-around_medium">
                        <ul>
                            <template for:each={finalData} for:item="acc">
                                <li key={acc.Id}>{acc.Name}
                                    
                                </li>
                            </template>
                        </ul>
                </div>
            </lightning-card>

        
      </template>

accountInfoComponent.js

import { LightningElement, track } from "lwc";
import { searchAccountByName, searchAccountById, searchAccountsByIds, fetchAccounts, fetchAllAccounts } from "c/accountService";


export default class AccountInfoComponent extends LightningElement {
    searchKey = '';
    searchKeyText = '';
    data = [];


    handleKeyChange(event) {
        this.searchKey = event.target.value;
    }

    //get all the accounts
    handleClick() {
        fetchAllAccounts()
            .then(result => {
                this.data = result;
                console.log(result);
            })
            .catch(error => {
                console.log(error.message);
            });
    }

    //get Account by Name
    handleSearchAccountByName() {
        this.fetchAccountByName(this.searchKey);
    }

    async fetchAccountByName(accountName) {
        try {
            let account = await searchAccountByName(accountName);
            this.data = account;
        } catch (err) {
            console.log(err);
        }
    }

    //get Account by Id
    handleSearchAccountById() {
        this.fetchAccountById(this.accountId);
    }

    async fetchAccountById(accountId) {
        try {
            let account = await searchAccountById(accountId);
            this.data = account;
        } catch (err) {
            console.log(err);
        }
    }

    //get Accounts by Ids
    handleSearchAccountsByIds() {
        this.fetchAccountsByIds(this.accountIds);
    }

    async fetchAccountsByIds(accountIds) {
        try {
            let accounts = await searchAccountsByIds(accountIds);
            this.data = accounts;
        } catch (err) {
            console.log(err);
        }
    }

    handleKeyTextChange(event){
        this.searchKeyText = event.target.value;
    }

    //get accounts by name with a search text on name
    handleSearchAccountsByName() {
        this.fetchAccountsByName(this.searchKeyText);
    }

    async fetchAccountsByName(accountName) {
        try {
            let accounts = await fetchAccounts(accountName);
            this.data = accounts;
        } catch (err) {
            console.log(err);
        }
    }

    get finalData(){
        console.log('wwww ' + JSON.stringify(this.data))    ;
        return this.data;
    }

}

accountInfoComponent.js-met.xml:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
    </targets>
</LightningComponentBundle>