Coding Patterns For Reusable Lightning Web Components – Factory Pattern

Hi, welcome to the first post in a series on what I think are great coding patterns that you can adopt when creating your own reusable Lightning Web Components or Lightning Components.

The first pattern I will go through is called the Factory Pattern.

A factory

Theory

This is a way of defining a set of generic behaviours and properties upfront, via an interface. You then design your component to work against what those generic behaviours and properties are, not against any domain-specific implementation. You then have a reusable asset that you can share with other developers, as instead of having to build the complete set of markup and client code, all they have to do is write an implementation of the interface that you defined.

The word factory comes into it as we need a factory class in the middle, which is a class that can broker, at runtime, what implementation of your interface the component asks for.

And that is kind of technical. I’ll try to explain it as if I were talking to a non technical friend or relative.

Imagine you are at a restaurant. That restaurant cooks and serves food. But upfront the restaurant doesn’t know what type of food you need. Let’s apply the factory pattern to that scenario.

The as-yet-unspecified meal that you want, that’s the interface. It will always be comprised of some food cooked by the kitchen. Before you decide what you want, it could be anything on the menu (each item would, therefore, be an implementation of the food interface).

You, as the customer, are the Lightning Web Component (lucky you). You want food. You choose your food, maybe you want a burger. You tell the waiter.

The waiter is, therefore, the factory class. They will take your order for a specific type of food and get it for you, in this case, its a burger.

A simple UML class map comparing Factory Pattern with the Real World example

Code

Here is a straightforward use case to demonstrate the concepts. Let’s imagine we want to have a button on a reusable, generic component that we are building. But we don’t know what that button will do as we are not responsible for developing the domain-specific implementation of that button. The things we need to do are more or less as follows:

  1. We need to create a simple lightning web component that has one button on it.
  2. We need to provide an interface for other developers to implement, that does a DML operation, using APEX.
  3. We need that interface to accept a recordId from the record page our component is placed on as a parameter.
  4. We need that interface to return some sort of parameter to the controller we are building to allow us to toast a message on the screen.
  5. We need to code the component against the interface definition.
  6. We need to add a design parameter to our component to enable the other developers to tell it what implementation of the interface we have created to use.

The first thing you will need to do is create a new Lightning Web Component in you project using the following sfdx command:

sfdx force:lightning:component:create -n jbtaFactoryDemo -d force-app/main/default/lwc --type lwc 

Then you can fill in the classes and files using the code below to get a working solution. You will also need to create 3 apex classes as you go through (I mention where this needs to be done as you go through).

jbtaFactoryDemo.html

This is just some basic lightning web component markup. It’s a button. It has an onclick event wired up. And it has a CSS class that makes it move to the right a “medium” bit.

<template>
    <lightning-card>
            <lightning-button name="Button" label="Label" onclick={actionButtonClicked} class="slds-m-left_medium" ></lightning-button>
    </lightning-card>
</template>

JbtaFactoryDemoButtonActionInterface.cls

You will need to create a new apex class here and call it JbtaFactoryDemoButtonActionInterface.

This is the interface I talked about a lot. Any class that implements this needs have a method called “executeRecordAction”, which needs an id parameter called recordContext, and it needs to return a string (which will be used when we display a toast a bit later).

public interface JbtaFactoryDemoButtonActionInterface {
    string executeRecordAction (id recordContext );
}

jbtaFactoryDemo.js

This is the component javascript file. It has two methods, one that calls a method called executeRecordAction which can be found in the counterpart apex controller. The callback will show a toast with whatever string is returned.

Note: @api implementaionClassName – this is the counterpart parameter for the input we have defined in the config file (force-jbtaFactoryDemo.js-meta.xml) – this is how we tell the factory class what class to use at runtime (i.e. what we order at the restaurant) and is what we type in when we drag the component on the page.

import { LightningElement, api, wire } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent'

import executeRecordAction from '@salesforce/apex/JbtaFactoryDemoController.executeRecordAction';


export default class JbtaFactoryDemo extends LightningElement {

    @api recordId;
    @api implementaionClassName ;

    actionButtonClicked(event) {
        executeRecordAction({ 
                instance: this.implementaionClassName
            ,   recordContext: this.recordId 
        }).then(result => {
                this.showToast('Success', result);
            })
            .catch(error => {
                this.showToast('Error', error);
            });
    }

    showToast (title, message) {
        console.log(message);
        const event = new ShowToastEvent({
            title: title,
            message: message,
        });
        this.dispatchEvent(event);
    }

}

JbtaFactoryDemoFactoryClass.cls

You will need to create a new apex class here and call it JbtaFactoryDemoFactoryClass.

This is a factory class that uses reflection to get the correct class that we specify when we add the component to the page.

public class JbtaFactoryDemoFactoryClass {

    
    public static JbtaFactoryDemoButtonActionInterface getRecordActionInstance (string className){
        Type t = Type.forName(className);
        
        if(t == null && className != null) {
            // Attempt to get the type again with the namespace explicitly set to blank
            t = Type.forName('', className);
        }
        if(t == null) {
            System.debug(LoggingLevel.Error, 'Failed to find type for ['+className+']');
            return null;
        }

        // Create an instance to confirm the type
        object testInstance = t.newInstance();
        if(!(testInstance instanceOf JbtaFactoryDemoButtonActionInterface)) {
            return null;
        }

        JbtaFactoryDemoButtonActionInterface interfaceInstance = (JbtaFactoryDemoButtonActionInterface)testInstance;
        return interfaceInstance;
        
    }
}

JbtaFactoryDemoController.cls

You will need to create a new apex class here and call it JbtaFactoryDemoController.

This is the final piece and it’s a simple controller. It just invokes the factory with whatever we pass through from the client-side code.

public with sharing class JbtaFactoryDemoController {

    @AuraEnabled
    public static string executeRecordAction (string instance, id recordContext) {
        JbtaFactoryDemoButtonActionInterface i = JbtaFactoryDemoFactoryClass.getRecordActionInstance(instance);
        return i.executeRecordAction(recordContext);
    } 

}

Deploy

If you have all the classes and files set up correctly you should be able to deploy the solution to you scratch org.

Demo

Here is a short demo of the component in action, enjoy.

I will further refine this solution and really start to scale this approach when we introduce Custom Metadata next week. I’m looking forward to writing that one up.

Thanks for reading, please add any comments or questions you have below.

Subscribe to this blog

Recent Posts

Chain of Responsibility Pattern in APEX

I was interested in seeing if this was possible in APEX, and was looking around for an implementation of this pattern and wasn’t able to find a reference, so I decided to just have a go and see what I could come up with

How to draw a system context diagram for your Salesforce project

Hello and welcome to the first post in a series of lessons on how to create excellent technical drawings for your Salesforce project. The first one is the System Context diagram, and I was inspired to start this while making toast for my children this morning.

Loading…

Something went wrong. Please refresh the page and/or try again.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s