Salesforce Development (LWC) : Creating a configurable Lightning Web Component using Custom Metadata
What is Custom Metadata and why would we create a configurable Lightning Web Component?
Custom Metadata is a wonderful thing. You set it up much like a custom object, but you use it for an entirely different purpose. Typically you use custom metadata much like you would utilize a config file in many other development languages. The nice part is, unlike a config file in normal coding languages where you have to write a bunch of XML, Salesforce does all that for you automatically. This custom metadata can be leveraged in your code to allow it to be dynamic and configurable. By utilizing it instead of hardcoding values into your code, you no longer need a developer to update code, but instead could have an admin update a few values in your custom metadata object. Noice!
As far as why we should strive to make our Lightning Web Components configurable instead of hardcoding values, it benefits us in the following ways:
1) Developers don’t have to waste time on simple updates, changing a label in the component or things like changing the default amount of rows shown in a table, can just be updated in the Custom Metadata files by an admin.
2) Updates take seconds instead of hours.
3) Removes the need to deploy components for small cosmetic updates.
There’s probably plenty more, but trust me… if you’re a developer who is tired of making boring garbage updates to your web apps, it’s time to start leveraging custom metadata types.
Configurable App Example: The LWC External Links Utility Bar App (My Open Source External Link App)
One of the most common things I’m asked to do with new Salesforce implementations is create a way for users to link out to other external applications within Salesforce. The first time I made this I hard-coded everything and when I ran into the exact same situation on my next client I decided I just need to make this configurable so I can drop it into any clients org with as little code as possible. I’m glad I made that choice because my next four clients asked for the exact same thing!
Thanks to custom metadata I’m able to dynamically do a lot of things without having to write hardly any code. The app can do the following with zero updates to the code:
1) Change the ordering of links
2) Determine whether to open the link in a browser tab or a Salesforce console tab
3) Determine whether the link should be added or removed from the link list
4) Change the URL for the link
5) Change the label for the link
Pretty toight am I roight?
So let’s get into the code and the custom metadata setup.
How to setup Custom Metadata Types
Setting up a custom metadata type is super easy to do. In Salesforce go to Setup -> Custom Metadata Types and then click the “New Custom Metadata Type” button once there. You’ll find setting up a custom metadata type very closely resembles setting up a custom object. Now as much as I appreciate everyone that reads this blog, I’m not gonna go into detail on how to set one one up. Primarily because Salesforce already has a particularly good trailhead for it. You can check it out here. If you watch the video linked above I also go into some brief detail as to how to do it.
Leveraging the Custom Metadata in your code
So how do we leverage this custom metadata in our code? Pretty simple. We query for its data in our Apex controllers just like we would for a custom object. In my custom external links component the apex code is this simple (you can also find this code and the custom metadata for it in this Github repository):
public with sharing class External_Links_Controller
{
@AuraEnabled
public static List<Utility_Bar_Link__mdt> getUtilityBarLinks()
{
return [SELECT MasterLabel, gAuto__Link_URL__c, gAuto__Open_in_console_tab__c,
gAuto__Order__c FROM gAuto__Utility_Bar_Link__mdt WHERE gAuto__Active_Link__c
= TRUE ORDER BY gAuto__Order__c ASC];
}
}
As you can see, we just query for the utility bar link custom metadata and return it to our LWC, but how exactly do we use it in our LWC?? Let’s check out the code for it as well.
<!--The HTML LWC Template -->
<template>
<!--Iterating through our list of external links and creating an input of type button
with data attributes that hold our important link information -->
<template if:true={linkList}>
<template for:each={linkList} for:item="link">
<input key={link.Id} data-id={link.Id} class="slds-button slds-
button_neutral linkButton" value={link.MasterLabel}
data-url={link.gAuto__Link_URL__c} data-opentab=
{link.gAuto__Open_in_console_tab__c} type="button" onclick=
{openLink}/>
</template>
</template>
</template>
/*The LWC Javascript Controller*/
import {LightningElement} from 'lwc';
//Importing our apex class method
import getUrlLinks from '@salesforce/apex/External_Links_Controller.getUtilityBarLinks';
//Importing the navigation mixin module so that we can navigate to new browser or console tabs
import {NavigationMixin} from 'lightning/navigation';
//Make sure to extend NavigationMixin here so that we can use it in the code
export default class ExternalLinksComponent extends NavigationMixin(LightningElement)
{
linkList;
//This method is rendered on the load of the component. I use it instead of @wire
//because @wire has a bug that sometimes causes Aura components in the same page
//to not be able to do DML transactions
connectedCallback()
{
//Calling our controller method to get our links and then assigning them to
//our linkList variable in the LWC controller
getUrlLinks().then(
result =>
{
this.linkList = result;
}
).catch( error =>
{
console.error('This is the error ::: ' + error);
});
}
//This method is called when one of the link buttons is clicked. It determines whether
//to open this link in a console tab or a browser tab
openLink(event)
{
//Getting the url for our link from the data-url attribute on the input button
//we clicked
let urlToPass = event.target.getAttribute("data-url");
//If the data-opentab attribute is true, we need to dispatch a custom event
//for our housing Aura component to handle
if(event.target.getAttribute("data-opentab") === "true")
{
const openTabEvent = new CustomEvent('opennewsubtab', {
detail: {urlToPass}
});
this.dispatchEvent(openTabEvent);
}
//Otherwise we need to open the url as a browser tab
else
{
//The standard__webPage NavigationMixin type allows us to open this in
//a new browser tab.
this[NavigationMixin.Navigate]({
type: 'standard__webPage',
attributes:{
url: urlToPass
}
});
}
}
}
/**
* LWC CSS
*/
.linkStyles
{
display: block;
text-align: center;
}
input:hover
{
color: rgba(27, 82, 151, 1);
text-decoration: none;
}
input:visited
{
text-decoration: none;
color: rgba(27, 82, 151, 1);
}
.linkButton
{
width: 100%;
height: 30px;
}
<!--
- Aura Component code. This is needed because LWC's do not currently have the ability to open Salesforce console tabs.
-->
<aura:component implements="force:appHostable, flexipage:availableForAllPageTypes, lightning:isUrlAddressable" access="global" description="External_Links_Wrapper">
<lightning:workspaceAPI aura:id="workspace"/>
<!--Adding our LWC and handling our custom event we declared in it (opennewsubtab)-->
<c:external_links_component onopennewsubtab="{!c.openConsoleTab}"/>
</aura:component>
/*Aura component javascript controller*/
({
//This function is utilized to open a new console tab within your console apps
openConsoleTab : function(component, event, helper)
{
//This finds the workspace for our current console app
let workspace = component.find("workspace");
//This opens the url as a tab in the console and auto focuses on that tab
workspace.openTab(
{
url: event.getParam("urlToPass"),
focus:true
}
);
}
});
So as you can see from the code above, the custom metadata determines basically every action that the LWC takes. Nothing is hard-coded for the most part, the actions are all determined by the custom metadata and the list of links comes directly from it as well.
There are two important things to note about this particular code that is unrelated to the concept of custom metadata.
1) An Aura component is included because LWC’s cannot current open console subtabs, so that must be handled in Aura.
2) Links can only be opened in a console tab if you can alter the websites Content Security Policy (CSP) to allow Salesforce to iFrame in your site. If you didn’t know, all data inside console tabs is iFrame’d in, there is no way to alter this behavior currently.
If you want more extremely detailed information on how this code actually works, please refer to the YouTube tutorial above. I go very in depth with the code, how the custom event passing works, etc.
Get Coding With The Force Merch!!
We now have a redbubble store setup so you can buy cool Coding With The Force merchandise! Please check it out! Every purchase goes to supporting the blog and YouTube channel.
Get Shirts Here!
Get Cups, Artwork, Coffee Cups, Bags, Masks and more here!
Check Out More Coding With The Force Stuff!
If you liked this post make sure to follow us on all our social media outlets to stay as up to date as possible with everything!
Youtube
Patreon
Github
Facebook
Twitter
Instagram
Salesforce Development Books I Recommend
Advanced Apex Programming
Salesforce Lightning Platform Enterprise Architecture
Mastering Salesforce DevOps