How I Built a Basic Salesforce Mobile App with Lightning App Builder
Tags: webdev, tutorial, salesforce, mobile
Published: 2022-03-31 12:10:02

![Article Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l0l0whp6ss0yhe3ix7rs.jpg)

In the fall of 2018, I decided to replace an application my mother-in-law was using for her real estate business. I decided to replace the application with an Angular client and Spring Boot service running inside of AWS. The biggest lesson I learned was that I felt like I spent more time trying to understand AWS and less time making enhancements to her application.

That all changed when spring 2020 arrived…

While the entire world was trying to figure out how to navigate amid a global pandemic, I was diving into the Heroku PaaS… and loving it. Within a very short period of time, I was able to move this same application over to Heroku. While I know that Heroku is using AWS behind the scenes, it has had zero impact on my time. I can stay focused on what I truly enjoy: adding value to custom applications and deploying new releases using basic git-based operations.

Though I understand Heroku is not an ideal choice in every situation, a large majority of the applications running today could take advantage of what Heroku has to offer and keep feature teams supporting those applications laser-focused on adding new functionality.

As I’ve started to do more work in the mobile app space, I wondered if there is a Heroku-like option for mobile app development for building Salesforce apps. I decided to take a look first at what the Salesforce Engineering team had to offer.

## About the Lightning App Builder

The Salesforce Lightning App Builder is a point-and-click tool to create single-page applications that can be used on mobile devices. Like what Heroku offers from an application hosting perspective, the Lightning App Builder product handles a majority of the application foundation. This allows developers to focus their time on meeting business needs and objectives.

The Lightning App Builder supports single-page applications that fall into one of three categories:

* App - used for custom applications
* Home - landing page upon login
* Record - page layout for a focused perspective of data

For this article, I will focus on the App option and create a brand new application.

## A “Stand Up” Use Case

In the three decades that I have been creating applications, I have been a member of more than my fair share of feature teams. During that time, I have found joy in hearing creative developers provide witty responses to the ever-popular team manager question, “Is it done yet?”

While agile teams don’t typically ask the question the same way that traditional project managers would, the need to communicate your current status is still part of the daily regimen for most feature developers. To help developers keep things fresh, we will create the “Stand Up” app using the Lightning App Builder.

Consider these high-level requirements:

1. Create a custom object (called Stand Up) to house the following information:
    A. Name (existing property) will be the response
    B. Type includes the following values to assign a type to the response:
        * Positive
        * Neutral
        * Negative

2. Create a Stand Up component and display four buttons:
    A. Positive
    B. Neutral
    C. Negative
    D. All

3. The basic flow of the app:

    A. Starting the app will present the four buttons (noted above)
    B. When the user selects a button, select a random response that matches the type property of the custom object. 
    C. The All button will select a random response across all three types.
    D. Display the response on the screen for the developer to relay during the daily stand-up session.

4. The App will run inside the Salesforce mobile client.

## Lightning App Builder in Action

With [Visual Studio (VS) Code](https://code.visualstudio.com/) running and the [Salesforce Extension Pack](https://marketplace.visualstudio.com/items?itemName=salesforce.salesforcedx-vscode) installed, getting started with the Stand Up app is as simple as using the Cmd+Shift+P (on my MacBook Pro) or Ctrl+Shift+P (Windows machines) and typing the following command:

`SFDX: Create Project`

To make things quick and easy, I selected the Standard option:

![Standard Option](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g7s2psqih1bg1w9yah5b.png)

I called my project **StandUpLightningWebComponent**:

![Name Component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rpc889y2l22wmwiahld9.png)

I placed the project into a folder called **stand-up-web-component** and opened a new workspace in VS Code:

![New VS Code Workspace](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f6txkd94ks3ov8j9lz4h.png)

Next, we need to connect to a Salesforce org, which I will use one of my existing sandboxes. If you need to create a new one, then check out the following URL:

https://developer.salesforce.com/signup

Once you have a developer org to use, you can then use the following Cmd+Shift+P/Ctrl+Shift+P command to connect VS Code to that org:

`SFDX: Authorize an Org`

VS code will prompt for a login URL option. I selected the Project Default option:

![Project Default Login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cnh7ryr38tr9e16c3irh.png)

When asked for a login alias, I simply hit the Enter key:

![Default Org Alias](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/da005s09n8l0ixe2lw74.png)

A browser window appeared, and I logged in to my sandbox org. The following dialog appeared:

![Org Successfully Authorized](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8qyntzcc9h8f3j7zow5p.png)

VS Code is now connected to my sandbox, and we are ready to get started with the Stand Up component.

### Creating the Stand Up Custom Object

Using the browser page that opened in the section above, I used the Salesforce Setup perspective to create a new custom object. If you happened to close that browser window, use the following VS Code Cmd+Shift+P/Ctrl+Shift+P command to open the default org in a browser window:

`SFDX: Open Default Org`

Within **Setup**, I simply navigated to **Objects and Fields | Object Manager**. Next, I used the **Create | Custom Object** option:

![Object Manager Home Screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/khxsmro4so3ei8elckme.png)

I created a new custom object with a label of **Stand Up** and kept the default object name of **Stand_Up**. However, I did replace the default Record Name value with **Witty Response**:

![Stand Up Custom Object](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/plfu52nwnwe4w56tg8aj.png)

I left default values for everything else, and I clicked the **Save** button to establish the new object.

![Stand Up Custom Object Created](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ksfzta5085qflky123sf.png)

In order to create the Type property, I navigated to the **Fields & Relationships** option and clicked the **New** button. For this field, I chose the **Picklist** option and clicked the **Next** button, which led to the following screen:

![Type Custom Field Options](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/slxohmkjwpxlwy67uukw.png)

The picklist will be limited to the three choices noted above. I clicked the **Next** button twice (to accept these values and the default field security), and then clicked the **Save** button to add the new field. The Stand Up object is ready for use:

![Stand Up Object Ready](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vip5xslu9wc5aawh0s0d.png)

Next, I used the **Integrations | Data Import Wizard** process in Salesforce to import the following records from the `sample-data.csv` file into the **Stand Up** custom object. 

```
All is good in the hood!,Positive
I am free and need something to work on.,Positive
Should be finished today.,Positive
Been battling a migraine - no update.,Neutral
It works but it hasn't been tested,Neutral
QA is testing things right now - fingers crossed.,Neutral
Still making progress - but not finished.,Neutral
Waiting for my merge-request to be approved.,Neutral
I am honestly thinking about a career change.,Negative
It is as done as it is gonna be - is that good enough?,Negative
My dog ate my code and I am starting over.,Negative
```

If you are unfamiliar with the process, you can read about how to use the import wizard here:

[Data Import Wizard](https://help.salesforce.com/s/articleView?id=sf.data_import_wizard.htm&type=5)

Once the import was completed, I create a file called `Stand_Up__c.soql` file inside the **Scripts | soql** section of VS Code, which contained the following contents:

```
// Use .soql files to store SOQL queries.
// You can execute queries in VS Code by selecting the
//     query text and running the command:
//     SFDX: Execute SOQL Query with Currently Selected Text

SELECT Id, Name, Type__c FROM Stand_Up__c ORDER BY Name ASC
```

Next, I highlighted the SELECT statement and used the Cmd+Shift+P/Ctrl+Shift+P command to select the following option:

`SFDX: Execute SOQL Query with Currently Selected Text`

This action produced the following results in my Terminal tab:

```
Starting SFDX: Execute SOQL Query...

12:29:51.99 sfdx force:data:soql:query --query SELECT Id, Name, Type__c FROM Stand_Up__c ORDER BY Name ASC


Querying Data... done


ID                  NAME                                                    TYPE__C
──────────────────  ──────────────────────────────────────────────────────  ────────
a092L00000E6eX4QAJ  Been battling a migraine - no update.                   Neutral
a092L00000E6eX2QAJ  I am free and need something to work on.                Positive
a092L00000E6eX9QAJ  I am honestly thinking about a career change.           Negative
a092L00000E6eXAQAZ  It is as done as it is gonna be - is that good enough?  Negative
a092L00000E6eX5QAJ  It works but it hasn't been tested                      Neutral
a092L00000E6eXBQAZ  My dog ate my code and I am starting over.              Negative
a092L00000E6eX6QAJ  QA is testing things right now - fingers crossed.       Neutral
a092L00000E6eX3QAJ  Should be finished today.                               Positive
a092L00000E6eX7QAJ  Still making progress - but not finished.               Neutral
a092L00000E6eX8QAJ  Waiting for my merge-request to be approved.            Neutral


Total number of records retrieved: 10.


12:29:52.681 sfdx force:data:soql:query --query SELECT Id, Name, Type__c FROM Stand_Up__c ORDER BY Name ASC
 ended with exit code 0
```

Finally, I wanted to pull all the metadata for the custom object into VS Code. This way, the custom object can be included in the git-based repository, eliminating the need for component users to create the object manually.

To import the Stand Up custom object into VS Code, use the following command from the Terminal window:

`sfdx force:source:retrieve -m CustomObject:Stand_Up__c`

The following output appeared in VS Code:

```
╭─jv@me ~/projects/jvc/stand-up-web-component/StandUpLightningWebComponent 
╰─$ sfdx force:source:retrieve -m CustomObject:Stand_Up__c                                                               
Preparing retrieve request... done
=== Retrieved Source
FULL NAME            TYPE          PROJECT PATH
────────────────── ──────────── ────────────────────────────────────────────────────────────────────────
Stand_Up__c.Type__c  CustomField   force-app/main/default/objects/Stand_Up__c/fields/Type__c.field-meta.xml
Stand_Up__c          CustomObject  force-app/main/default/objects/Stand_Up__c/Stand_Up__c.object-meta.xml
```

It is also possible to achieve the same result in VS Code by clicking the cloud icon in the toolbar, locating the items you wish to retrieve and pushing the download icon.

On the left-hand side of VS code, the Stand Up custom object is now available:

![Object visible in VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sukqxgt3391sfbw0ztev.png)

With the object and data ready, we can build the Lightning Web Component which will be used with the app.

### Creating the Stand Up Controller

We will create the Stand Up controller first, which will act as an API to locate the appropriate response.

We can use the following Cmd+Shift+P/Ctrl+Shift+P command to create the **StandUpController** class:

`SFDX: Create Apex Class`

I populated the simple controller as noted below:

```
public with sharing class StandUpController {
    @AuraEnabled(cacheable=false)
    public static Stand_Up__c getRandomResponse(String responseType) {
        List<Stand_Up__c> responseList;

        if (responseType.equals('all')) {
            responseList = [SELECT Name, Type__c FROM Stand_Up__c];
        } else {
            responseList = [SELECT Name, Type__c FROM Stand_Up__c WHERE Type__c = :responseType];
        }

        return getRandomFromList(responseList);
    }

    private static Stand_Up__c getRandomFromList(List<Stand_Up__c> responseList) {
        if (responseList == null || responseList.isEmpty()) {
            Stand_Up__c standUpResponse = new Stand_Up__c();
            standUpResponse.Name = 'Ummmm.......';
            standUpResponse.Type__c = 'Neutral';

            return standUpResponse;
        }

        Integer count = responseList.size();
        Integer rand = Math.floor(Math.random() * count).intValue();

        return responseList[rand];
    }
}
```

The client will call the `StandUpController.getRandomResponse() `method, passing in the appropriate `responseTyp`e option, which will return a `Stand_Up__c` record. If there are no records available to match the request, then a new `Stand_Up__c` object will be returned with the neutral status of simply “Ummmm.......”

### Creating the Stand Up Lightning Web Component

We are now ready to create the Lightning Web Component for the Stand Up app.

We can use the following Cmd+Shift+P/Ctrl+Shift+P command to create the standUp Lightning Web component:

`SFDX: Create Lightning Web Component`

The first thing we need to do is update the `standUp.js-meta.xml` to make this component available for use:

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

Next, the `standUp.js` needs to be updated to process requests by the app, interacting with the controller we created in the last section:

```
import { LightningElement } from 'lwc';
import getRandomResponse from '@salesforce/apex/StandUpController.getRandomResponse';

export default class StandUp extends LightningElement {
    standUpResponse = null;
    error = null;

    getPositiveResponse() {
        this.getRandomResponseFromSalesforce('Positive');
    }

    getNeutralResponse() {
        this.getRandomResponseFromSalesforce('Neutral');
    }

    getNegativeResponse() {
        this.getRandomResponseFromSalesforce('Negative');
    }

    getAnyResponse() {
        this.getRandomResponseFromSalesforce('all');
    }

    getRandomResponseFromSalesforce(responseType) {
        this.standUpResponse = null;
        this.error = null;
        getRandomResponse({responseType})
        .then((standUp) => {
            this.standUpResponse = standUp.Name;
        })
        .catch((error) => {
            this.error = JSON.stringify(error);
        });
    }
}
```

Finally, we need to update the `standUp.html` file to include the view-layer logic:

```
<template>
    <div class="slds-var-m-vertical_large slds-var-p-vertical_medium 
    slds-text-align_center slds-border_top slds-border_bottom slds-text-heading_small">
        <p>Select the type of update you wish to find: </p>
    </div>

    <div class="slds-text-align_center slds-var-p-top_xx-small">
        <lightning-button variant="brand" class="slds-var-m-left_x-small"
            icon-name="utility:cases" label="Positive" title="Positive"
            onclick={getPositiveResponse}>
        </lightning-button>
    </div>
    <div class="slds-text-align_center slds-var-p-top_xx-small">
        <lightning-button variant="brand" class="slds-var-m-left_x-small"
            icon-name="utility:cases" label="Neutral" title="Neutral"
            onclick={getNeutralResponse}>
        </lightning-button>
    </div>
    <div class="slds-text-align_center slds-var-p-top_xx-small">
        <lightning-button variant="brand" class="slds-var-m-left_x-small"
            icon-name="utility:cases" label="Negative" title="Negative"
            onclick={getNegativeResponse}>
        </lightning-button>
    </div>
    <div class="slds-text-align_center slds-var-p-top_xx-small">
        <lightning-button variant="brand" class="slds-var-m-left_x-small"
            icon-name="utility:cases" label="Any" title="Any"
            onclick={getAnyResponse}>
        </lightning-button>
    </div>

    <div if:true={standUpResponse} class="slds-var-m-vertical_large slds-var-p-vertical_medium 
    slds-text-align_center slds-border_top slds-border_bottom slds-text-heading_small">
        <p>Today's Update: {standUpResponse}</p>
    </div>

    <div if:true={error} class="slds-var-m-vertical_large slds-var-p-vertical_medium 
    slds-text-align_center slds-border_top slds-border_bottom slds-text-color_error">
        <p>Error: {error}</p>
    </div>
</template>
```

Now, we are ready to deploy the Stand Up app to Salesforce.

### Deploying to Salesforce

Pushing all my code from the local machine to Salesforce is simple. All I need to do is right click on the **force-app/main/default** in the navigator and select the **SFDX: Deploy Source to Org** option:

![Deploy to Salesforce](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0kc1ltzrhfdul4xtb773.png)

Once completed, the following dialog will appear in VS Code:

![Deployed to Salesforce](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iceloeb9s452p0o46dcz.png)

Now we are ready to add the Lightning Web Component to a new app in Salesforce.

### Creating a New Lightning App in Salesforce

I switched over to the browser tab logged into my Salesforce org and opened the **Setup** perspective. Next, I navigated to the **Apps | App Manager** page and clicked the **New Lightning App** button. 

![New Lightning App](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/55z41o3aybpzqcpcalfx.png)

I decided to call the new app Stand Up and even found a nice little icon to use. I used the rest of the default settings from the wizard, except the last screen, where I granted all users access to this app.

Then, I navigated to the **User Interface | Lightning App Builder** screen. Here, I created a new **Lightning App Page** called **Stand Up**, which was designed as an **App Page** with a single region. 

On the left side of the screen, I could see my standUp 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.

![Lightning App Builder with LWC Placed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/we5ivhw3gbgnzoay1ocg.png)

After saving the component, I used the activation process to expose the Lightning page for clients to utilize. 

During the activation phase, I set the App Name to **Stand Up** and found the best icon on the list:

![Activation Page Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3snjvbwmidjwvdxveekf.png)

To set up the Lightning Experience, I dropped the Stand Up app onto the right side of the screen:

![Activation Lightning Experience](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3p6qtbc0xut6nlm8p439.png)

For the Mobile Navigation, I added the **Stand Up** Lighting app and made sure it was near the top of the list:

![Activation Mobile Navigation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zvnh02rjfxl01nw3ksb4.png)

After hitting the **Save** button, the Stand Up app was ready for use.

## Using the Stand Up App

After launching the Salesforce mobile app, I was able to see the Stand Up app I just created:

![Salesforce Mobile App Menu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ts55vwqg44aaurr57c8m.jpg)

Next, I tapped the **Stand Up** application, which displayed the following screen with my custom LWC:

![Stand Up Initial Screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/do6xbnee0o82dfikbbvk.jpg)

Tapping the **Any** button will return a random response from the `Stand_Up__c` record set:

![Stand Up App - Any Button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uq6itmtzv3qet3idn421.jpg)

The app is also available for use in Salesforce, without making any updates to the code:

![Stand Up App - Browser](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/70hkh53u8986w316jelh.png)

## Conclusion

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

Just like I found with my evaluation of the Heroku platform, I was able to quickly introduce a Salesforce mobile app by leveraging the Salesforce platform. In doing so, I remained focused on meeting the needs of the application rather than worrying about foundational and design decisions.

Truly, this pattern adheres to my mission statement … and the time required to complete this example was measured in minutes instead of hours or even days.

If you are interested in the source code for this article, simply navigate to the following repository on GitLab:

https://gitlab.com/johnjvester/stand-up-web-component

Have a really great day!