Sample Gallery Updates for Spring ’20

As usual, Spring arrives early for the Salesforce world, and with it, our latest release. During this prerelease cycle, the developer evangelist team has been busy updating our gallery of sample apps with the latest and greatest features. Here’s a list of items that you can find if you pull down the latest from GitHub.

What is the Sample Gallery?

The Sample Gallery is a set of reference apps that showcase a range of low-code to pro-code developer features of the Salesforce platform. Each sample app takes an idea and implements it in the Salesforce platform along with other related apps and features e.g. mobile apps, external-facing web apps, integrations, etc. You can read about all the apps on the Sample Gallery landing page, which also contains links to source repos for each app.

LWC Properties Are Automatically Reactive

In Spring ‘20, the Lightning Web Component core framework has an added feature that makes all properties reactive without the need to be explicitly decorated as such. In the past, where you would have seen @track used to trigger a DOM refresh in LWC, this becomes no longer necessary. To address this, we’ve removed the @track decorator.

The code below from the todoList component in the LWC Recipes app shows one instance of how this looks in our sample apps.

Previously, the filteredTodos array property was decorated with @track.

    @track filteredTodos = [];

Again, with the new “all properties are reactive” feature, this is no longer necessary; with one important exception.

You must use @track to observe changes in the properties of an object or elements of an array. In other words, if you mutate an object or array in place and you want to update the DOM based on that, @track is required.

Understanding array or object mutation in JavaScript is not always straightforward. However, every instance of our sample apps follows the practice of not mutating objects or arrays in place, but rather reassigning them when we need to change their state. In the filteredTodos example above, we have removed @track.

import { LightningElement, api } from 'lwc';

export default class TodoList extends LightningElement {

    filteredTodos = [];

    _todos = [];

    ...
    
    filterTodos() {
        if (this.priorityFilter) {
            // the line below creates a new array instance triggering 
            // the implicitly reactive property
            this.filteredTodos = this._todos.filter(
                todo => todo.priority === true
            );
        } else {
            this.filteredTodos = this._todos;
        }
    }

    ...
}

When the filterTodos() function is invoked, we use the Array.prototype.filter() higher order function on the “master” list of todo items in the private _todos array. The filter function always returns a new array instance, meaning the line this.filteredTodos = this._todos.filter... will always cause a new object to be assigned to this.filteredTodos and trigger the now implicit reactivity of that property.

But be careful, some higher-order array functions (like Array.prototype.sort()) modify an array in place. If you find yourself using one of these, you might want to look into explicitly creating a new array or alternatively, actually use the @track decorator on that array.

For more on the implementation of reactive data types in LWC, we recommend reading the documentation on that topic from the LWC open source project.

Lightning Pages on Desktop and Mobile

Prior to Spring ‘20, there was no easy way to bring Lightning Pages to mobile. Now, you can design your Lightning Pages for mobile as well as desktop. This includes some of the standard templates, but you can also raise the bar by creating your own custom templates.

To bring this to life, we updated the custom Lightning page template in the Dreamhouse app.

        <aura:if isTrue="{!not($Browser.isPhone)}">
            <!-- If Tablet or Desktop, 2-7-3 regions -->
            <lightning:layout>
                ...
            </lightning:layout>
        </aura:if>
        <aura:if isTrue="{!$Browser.isPhone}">
            <!-- If Phone, single region -->
            <lightning:layout>
                ...
            </lightning:layout>
        </aura:if>

Custom page templates are implemented in Aura today. Above you can see the markup used to define whether the template will use a layout that supports desktop or mobile, based on information provided by the browser.

We reviewed components and modified any we needed to in order for them to work in a small form factor. In addition to ensuring the components themselves were responsive, we also needed to configure the metadata file to indicate which form factors a given component supports.

<LightningComponentBundle>
...
            <supportedFormFactors>
                <supportedFormFactor type="Large" />
                <supportedFormFactor type="Small" />
            </supportedFormFactors>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

Finally, we configured the app as well as several record pages to be available for mobile, and we were now all set for our pages to work in both mobile and desktop.

Check In Your Community

For developers working with Communities, the Communities Experience Bundle is a long awaited improvement to your application lifecycle management. This new way to store your community configuration creates a bundle of files which allows you to build, configure, and customize your community as well as check the entire configuration in version control, in a JSON-based format. No more binary .site file!

This change also now makes it possible to create and test your community in a scratch org and manage its deployment from the Salesforce CLI. The experience bundle feature has been in closed pilot… until now. In moving to being generally available, the experience bundle feature adds support for unlocked packages, as well as support for additional Communities configurations that weren’t in the pilot. You can see this in use and test it out in the e-bikes sample app.

Please note that the effort to migrate an existing community to the experience bundle format varies greatly between orgs. If you decide to make the transition, be sure to budget time to investigate how this change will impact you.

If you would like to read more about using the experience bundle, be sure to check out the Communities developer guide, or read about the implementation specs in the Metadata API developer guide. You can also watch this segment on experience bundles from the release readiness live webinar.

SOQL SECURITY_ENFORCED Queries

Apex has been introducing some exciting new features, and nothing is more exciting to you (and your compliance team) than more secure data access. While some of these are still in beta, we’re pleased to include the new SOQL WITH SECURITY_ENFORCED clause in most Apex classes that use SOQL (where the SOQL fits the restrictions of that feature) Here’s an example:

    @AuraEnabled(cacheable=true)
    public static List<Contact> findContacts(String searchKey) {
        String key = '%' + searchKey + '%';
        return [
            SELECT Id, Name, Title, Phone, Email, Picture__c
            FROM Contact
            WHERE Name LIKE :key AND Picture__c != null
            WITH SECURITY_ENFORCED
            LIMIT 10
        ];
    }

The WITH SECURITY_ENFORCED clause allows you to bring object and field security into your Apex SOQL queries with one simple statement. There are a few rules around using it correctly, so be sure to check out the documentation and the release notes for implementation details. A segment from the release readiness webinar that covers the new Apex security features can be seen here.

Navigating to New Records with Default Values

The term “url hack” has long been fabled in the annals of Salesforce developer lore as a by-the-seat-of-your-pants “pattern”.

Well, hack no longer!

In Lightning, both Aura and LWC components support the ability to navigate to a new record with default values.

We’ve implemented this in its own recipe in the LWC Recipes app.

import { LightningElement } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
import { encodeDefaultFieldValues } from 'lightning/pageReferenceUtils';

export default class NavToNewRecord extends NavigationMixin(LightningElement) {
    navigateToNewContactWithDefaults() {
        // get encoded default values
        const defaultValues = encodeDefaultFieldValues({
            FirstName: 'Morag',
            LastName: 'de Fault',
            LeadSource: 'Other',
            AccountId: '011xxxxxxxxxxxxXXX'
        });

        console.log(defaultValues);

        this[NavigationMixin.Navigate]({
            type: 'standard__objectPage',
            attributes: {
                objectApiName: 'Contact',
                actionName: 'new'
            },
            state: {
                // assign default values for nav pageReference
                defaultFieldValues: defaultValues
            }
        });
    }
}

Note that for the time being, sfdx-lwc-jest framework does not support the lightning/pageReferenceUtils package, so we’ve implemented a dummy test. We will however be updating this once a better solution appears.

 

When initiating navigation, the PageReference supports a state value to set default values, and the lightning/pageReferenceUtils utility has been added to correctly encode and decode default values. In Aura, this utility is referenced in markup as a component called <lightning:pageReferenceUtils/>

Other Items of Note

Coming Changes to the sample apps

We’re constantly working to improve our sample apps for you. Some great things are planned to ship throughout this year. If you want to get a sneak peak of one of these you should check out Trailhead Live, where developer evangelist Kevin Poorman codes live on…drumroll…Apex Recipes! Stay tuned!

You too can contribute

If you have an idea for a feature to add to a sample app, or see a bug or potential improvement, we welcome your contributions to the sample apps! Details for how to contribute are located in each sample app repo. So if you see something, file an issue and we can discuss it with you; if you can write the solution, we welcome the PRs.

Summing It Up

As always, releases are a bit like a birthday present that comes three times a year. We hope you enjoy exploring these features in the Sample Gallery as we all include Spring ‘20 to our orgs.