Mobile devices have become a core aspect of our lives. Of course, this can be a good and bad thing. However, for the purposes of this article, I’ll focus on the positive ways mobile devices enrich our lives.
In fact, when my college-senior son, Eric visits, our conversations often provoke Eric to use his phone to locate and validate information related to our discussions. The crazy thing is: No matter what we talk about, his favorite search engine and voice-to-text skills provide an almost-immediate answer.
This made me wonder how easily I could implement barcode technology into a custom application or component.
The engineering team at Salesforce knows that barcodes are a quick and easy way for mobile device users to pinpoint information. Both UPC barcodes and QR codes have been in place for decades now, and their usage isn’t fading.
Using the Salesforce mobile client and the camera on the mobile device, barcodes can be easily integrated into an application via the BarcodeScanner API. Here are a few common use cases for creating a Lightning Web Component (LWC) which includes the BarcodeScanner API:
In this article, I’ll explore the first option, where the scanned barcode performs a lookup for data stored inside of Salesforce.
Salesforce DX makes development on the Salesforce Platform easy, open, integrated, and collaborative. With Salesforce DX, developers can build together and deliver continuously. When coupled with Visual Studio (VS) Code and the Salesforce Extension Pack, working with Salesforce becomes a seamless operation.
As an example, the Command-Shift-P or Windows-Shift-P shortcut provides a quick access to SFDX commands like those shown below:
Seeing these enhancements first-hand excited me for an opportunity to use VS Code and the Salesforce Extension Pack to build something for the Salesforce platform.
My avid readers may recall that I have the opportunity to work in a 100% remote role. For the majority of the week, I share our home with my wife, Nicole, and our toddler son, Finny.
Nicole is very conscientious about maintaining a good diet, and my love of snacks is a sensitive topic between us. This is basically a nice way of saying that Nicole thinks I snack too much.
What I noticed is that each of these snacks …
… has its own unique barcode.
Given my current scenario, I decided to create a Lightning Web Component (LWC) for a Salesforce mobile application called Calorie Counter. This application would use the BarcodeScanner API to read the UPC and provide the number of calories for the snack of my choosing.
Long term, I could use this logic to track my snack consumption, helping me to stay within an acceptable range. However, for now, we’ll walk before we run.
To keep things simple, I created a Snack__c
object in Salesforce DX, which contained the following properties:
Calories__c
) to note the calories per servingUPC__c
) to serve as a unique key for each snack
Using my snacks (pictured above) I could quickly enter the expected data for this use case:
With an understanding of my data structure and simple use case, I outlined the next steps:
Snack__c
object using the barcode value.Snack__c
result exists for the scanned value, then return the object data to the LWC.Within VS Code, a new LWC can be created using the SFDX: Create Lightning Web Component option. I used the name calorieCounter
.
First, I wanted to make sure that my new component could be used pretty much anywhere in the Salesforce ecosystem. I updated calorieCounter.js-meta.xml
as shown below:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>53.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
The BarcodeScanner API was added to my new component using the following information contained in the BarcodeScanner API documentation:
import { getBarcodeScanner } from 'lightning/mobileCapabilities';
Next, I added the following method to determine if the client using the component can scan barcodes:
connectedCallback() {
this.myScanner = getBarcodeScanner();
if (this.myScanner == null || !this.myScanner.isAvailable()) {
this.scanButtonDisabled = true;
}
}
Finally, I added the handleBeginScanClick()
method to capture a barcode from the device camera. Then, if successful, the results are passed to an Apex controller in Salesforce to attempt to locate a snack. I also added simple error handling.
handleBeginScanClick(event) {
// Reset scannedBarcode to empty string before starting new scan
this.scannedBarcode = '';
this.resultsFound = false;
this.snackFound = false;
// Make sure BarcodeScanner is available before trying to use it
// Note: We _also_ disable the Scan button if there's no BarcodeScanner
if (this.myScanner?.isAvailable()) {
const scanningOptions = {
barcodeTypes: [
this.myScanner.barcodeTypes.UPC_E
]
};
this.myScanner
.beginCapture(scanningOptions)
.then((result) => {
this.resultsFound = true;
this.scannedBarcode = result.value;
this.scannedBarcodeType = result.type;
findSnackByUpcEquals({ upcId: this.scannedBarcode })
.then((snack) => {
this.snackFound = true;
this.snackName = snack.Name;
this.snackCalories = snack.Calories__c;
this.snackUPC = snack.UPC__c;
this.error = undefined;
this.buttonLabel = 'Scan Another Snack Barcode';
})
.catch((error) => {
throw error;
});
})
.catch((error) => {
// Handle cancellation and unexpected errors here
console.error(error);
this.snackFound = false;
this.buttonLabel = 'Scan Barcode';
// Inform the user we ran into something unexpected
this.dispatchEvent(
new ShowToastEvent({
title: 'Barcode Scanner Error',
message:
'There was a problem scanning the barcode: ' +
JSON.stringify(error) +
' Please try again.',
variant: 'error',
mode: 'sticky'
})
);
})
.finally(() => {
// Clean up by ending capture,
// whether we completed successfully or had an error
this.myScanner.endCapture();
});
} else {
// BarcodeScanner is not available
// Not running on hardware with a camera, or some other context issue
// Let user know they need to use a mobile phone with a camera
this.dispatchEvent(
new ShowToastEvent({
title: 'Barcode Scanner Is Not Available',
message:
'Try again from the Salesforce app on a mobile device.',
variant: 'error'
})
);
}
}
This is what the template for the simple component UI looks like:
<template>
<div if:false={resultsFound} class="slds-align_absolute-center slds-text-align_center
slds-text-color_weak">
Click the Scan Barcode button to open a barcode scanner camera view. Position a barcode in the scanner view to scan it.
</div>
<div if:true={resultsFound} class="slds-var-m-vertical_large slds-var-p-vertical_medium
slds-text-align_center slds-border_top slds-border_bottom">
<p>Found Barcode = {scannedBarcode} (type = {scannedBarcodeType})</p>
</div>
<div if:true={snackFound} class="slds-var-m-vertical_large slds-var-p-vertical_medium
slds-text-align_center slds-border_top slds-border_bottom">
<div class="slds-m-around_medium">
<p><span class="slds-text-title_bold">Name</span>: {snackName}</p>
<p><span class="slds-text-title_bold">Calories</span>: {snackCalories}</p>
<p><span class="slds-text-title_bold">UPC Value</span>: {snackUPC}</p>
</div>
</div>
<div class="slds-text-align_center slds-p-top_xx-small">
<lightning-button variant="brand" class="slds-var-m-left_x-small" disabled={scanButtonDisabled}
icon-name="utility:cases" label={buttonLabel} title="Scan a Snack"
onclick={handleBeginScanClick}>
</lightning-button>
</div>
</template>
The Apex controller used by the calorie counter component is simple in design as well, basically containing a single Salesforce query:
public with sharing class SnackController {
@AuraEnabled(cacheable=true)
public static Snack__c findSnackByUpcEquals(String upcId) {
return [
SELECT Name, Calories__c, UPC__c
FROM Snack__c
WHERE UPC__c = :upcId
LIMIT 1
];
}
}
The controller receives the upcId
from the component and includes the value in the query of the Snack__c
object. The result set is limited to one record, which is returned to the component.
Once ready, I was able to use Command-Shift-P and the SFDX: Deploy This Source to Org command to push my code to my Salesforce development org. This allowed the snack object, calorie counter component, and Apex controller to be available for use within Salesforce.
Next, I opened the Setup perspective in Salesforce and navigated to the Apps | App Manager page. I clicked the New Lightning App button and created a new application called CalorieCounter
:
Then, I navigated to the User Interface | Lightning App Builder screen. Here, I created a new Lightning Page called Calorie Counter
, which was designed as an App Page with a single region.
On the left side of the screen, I could see my calorieCounter
LWC under the Custom section. All I had to do was drag that component over and drop it into the single region for the Lightning-based page.
After saving the component, I used the activation process to expose the Lightning page for clients to utilize. During the activation phase, I added the Calorie Counter Lightning page to the CalorieCounter
app:
Finally, I visited the Setup | Apps | Mobile Apps | Salesforce Navigation and added the Calorie Counter app near the top of the selected apps:
After downloading and launching my Salesforce mobile app, I could see the Calorie Counter application I just created:
Next, I tapped the Calorie Counter application, which displayed the following screen with my custom LWC:
I tapped the Scan Barcode button and scanned the UPC for the Hershey bar:
The barcode scanner on my mobile device quickly recognized the barcode and updated the Calorie Counter application as shown below:
Within a matter of seconds, I was able to look up the calories for the Hershey bar and make the decision if that was a snack I was ready to eat. (I was, and I did.)
Starting in 2021, I have been trying to live by the following mission statement, which I feel can apply to any IT professional:
“Focus your time on delivering features/functionality which extends the value of your intellectual property. Leverage frameworks, products, and services for everything else.”
- J. Vester
The ability to introduce barcode support into a custom application is quite simple when utilizing Lightning Web Components (LWC) and the BarcodeScanner API.
In less than an hour, my knowledge of barcodes went from a casual scanner to a developer who just integrated barcodes into a functional application. Clearly, the engineering team at Salesforce is developing solutions that provide real-world value to common challenges… and they also help me live within my current mission statement.
In today’s world, consumers are driven by what they can and cannot do on their mobile devices. If there is a way for barcode technology to give you a competitive advantage, an application platform (like Salesforce) that offers a solid barcode API should be on your short list of providers to consider.
If you are interested in the source code for this article, simply navigate to the following repository on GitLab:
https://gitlab.com/johnjvester/lwc-calorie-counter
Have a really great day!
Co-published here.