Release Updates

 

Winter 23

 

Permission Set or Permission Set Group Expirations

Now you can assign an expiration date to each permission set or permission set group. 

·       To activate this feature, enable Permission Set & Permission Set Group Assignments with Expiration Dates in User Management Settings.

·       If a permission set or permission set group contains any of the following permissions, it can’t have an expiration date associated with it. Assign Permission Set, Manage Profiles, Manage Users Permission Sets

·       Example

o   Suppose you need consultants in the San Francisco office to evaluate language used in sales contracts. Assign the consultants to a permission set group that contains the permissions that they need. When you assign the consultants to the group, specify that the assignment expires in 30 days (GMT-07:00) Pacific Daylight Time (America/Los Angeles). If you assign the permissions on June 1, the assignments expire on June 30 at 11:59 PM Pacific Time.

 

 

 

 

 

System.Domain Class

 

To obtain information about domains that Salesforce hosts for your org, use the methods in the new System.Domain class.

For example, for a sandbox domain, the getSandboxName() method returns the name of the sandbox. And the getDomainType() method returns the associated System.DomainType enum value, which represents the type of domain, such as CONTENT_DOMAINEXPERIENCE_CLOUD_SITES_DOMAIN, or LIGHTNING_DOMAIN.

 

 

LWC [Winter 23]

 

Create Notifications with New Alert, Confirm, and Prompt Modules

Use the new modules LightningAlert, LightningConfirm, and LightningPrompt instead of native APIs to create notifications from your Lightning web components. Chrome and Safari plan to end support for cross-origin use of the window.alert(), window.confirm(), and window.prompt() native APIs. Each new module creates a modal that functions like its API counterpart and works in cross-origin iframes.

How: Unlike the window.*() APIs, these modules' .open() functions don’t halt execution on the page, and they each return a promise. Use async/await or .then() for any code that you want to execute after the modal closes.

These examples show how to use LightningAlert, LightningConfirm, and LightningPrompt in Lightning web components. See New and Changed Aura Components for examples using Aura syntax with the lightning:alert, lightning:confirm, and lightning:prompt components.

 

LightningAlert Example

This example creates an alert modal with an error message and OK button. The .open() function returns a promise that resolves when the user clicks OK.

<!-- c/myApp.html -->

<template>

    <lightning-button onclick={handleAlertClick} label="Open Alert Modal">

    </lightning-button>

</template>

Copy

// c/myApp.js

import { LightningElement } from 'lwc';

import LightningAlert from 'lightning/alert';

export default class MyApp extends LightningElement {

    async handleAlertClick() {

        await LightningAlert.open({

            message: 'this is the alert message',

            theme: 'error', // a red theme intended for error states

            label: 'Error!', // this is the header text

        });

        //Alert has been closed

    } }

 

LightningConfirm Example

 

This example creates a headerless confirm modal with two buttons, OK and Cancel. The .open() function returns a promise that resolves to true when the user clicks OK and false when they click Cancel.

<!-- c/myApp.html -->

<template>

    <lightning-button onclick={handleConfirmClick} label="Open Confirm Modal">

    </lightning-button>

</template>

Copy

// c/myApp.js

import { LightningElement } from 'lwc';

import LightningConfirm from 'lightning/confirm';

export default class MyApp extends LightningElement {

    async handleConfirmClick() {

        const result = await LightningConfirm.open({

            message: 'this is the prompt message',

            variant: 'headerless',

            label: 'this is the aria-label value',

            // setting theme would have no effect

        });

        //Confirm has been closed

        //result is true if OK was clicked

        //and false if cancel was clicked

    }

}

 

LightningPrompt Example

This example creates a prompt modal with a header, message, and two buttons. If the user inputs text and clicks OK in the prompt, the .open() function returns a promise that resolves to the input value, but if the user clicks Cancel it resolves to null.

<!-- c/myApp.html -->

<template>

    <lightning-button onclick={handlePromptClick} label="Open Prompt Modal">

    </lightning-button>

</template>

Copy

// c/myApp.js

import { LightningElement } from 'lwc';

import LightningPrompt from 'lightning/prompt';

export default class MyApp extends LightningElement {

    handlePromptClick() {

        LightningPrompt.open({

            message: 'this is the prompt message',

            //theme defaults to "default"

            label: 'Please Respond', // this is the header text

            defaultValue: 'initial input value', //this is optional

        }).then((result) => {

            //Prompt has been closed

            //result is input text if OK clicked

            //and null if cancel was clicked

        });

    }

}

 

 

Winter 23 Reference Links

 

TrailHead Link PD1

 

 


 

 

Spring 23

 

SOQL

              Query runs in user mode, use the WITH USER_MODE keyword in your SOQL statement.  

                           Example: List acc = [SELECT Id FROM Account WITH USER_MODE];

Apex              

              DML operations, you now specify user mode as shown below.

                           Example

Account acc = new Account(Name='test');

                                         insert as user acc;

Queueable Job         

              Specify a delay in scheduling queueable jobs, enabling you to not consume async limits rapidly

                           Example

Integer delayInMinutes = 5;

                                         ID jobID = System.enqueueJob(new MyQueueableClass(), delayInMinutes);

 

 

DynamicBinding Variables

                           Database.queryWithBinds, Database.getQueryLocatorWithBinds, and Database. countQueryWithBinds

             

              Example:  The SOQL query uses a bind variable for an Account name. Its value (Acme Inc.) is passed into the method using the nameBind Map. The accountName variable isn't (and doesn’t have to be) in scope when the query is executed within the method.

 

              public static List<Account> simpleBindingSoqlQuery(Map<String, Object> bindParams) {

                           String queryString =

                                         'SELECT Id, Name ' +

                                         'FROM Account ' +

                                         'WHERE name = :name';

                           return Database.queryWithBinds(

                                         queryString,

                                         bindParams,

                                         AccessLevel.USER_MODE

                           );

              }

 

              String accountName = 'Acme Inc.';

              Map<String, Object> nameBind = new Map<String, Object>{'name' => accountName};

              List<Account> accounts = simpleBindingSoqlQuery(nameBind);

              System.debug(accounts);

 

 


 

Find Which Apex Classes Implement an Interface

ApexTypeImplementor is now generally available and is updated since the beta release. Use the object to find Apex classes that directly or indirectly implement an interface. Using a SOQL query, you can get information about public or global Apex implementors.

 

 

// Common interface that all rounding strategies will implement

public interface RoundingStratergy {

    Decimal round(Decimal toRound);

}

 

public abstract class RoundingStrategies {

    public class Ceiling implements RoundingStratergy {

        public Decimal round(Decimal toRound) {

            return toRound.round(System.RoundingMode.CEILING);

        }

    }

   

    public class HalfDown implements RoundingStratergy {

        public Decimal round(Decimal toRound) {

            return toRound.round(System.RoundingMode.HALF_DOWN);

        }

    }

   

    public class TwoDecimalPlaces implements RoundingStratergy {

        public Decimal round(Decimal toRound) {

            return toRound.setScale(2, System.RoundingMode.HALF_UP);

        }

    }

}

 

List<ApexTypeImplementor> interfaceImpls = [

            SELECT ClassName, ClassNamespacePrefix

            FROM ApexTypeImplementor

            WHERE InterfaceName = 'RoundingStratergy' and IsConcrete=true];

       

// For example, an Admin could be presented with a list of Apex classes

// that could be applied. Simulated selection of 2 decimal places

ApexTypeImplementor selectedRoundingStratergy = interfaceImpls[2];

System.assertEquals('RoundingStrategies.TwoDecimalPlaces',

    selectedRoundingStratergy.ClassName);

       

// Create an instance of the class that implements the interface

RoundingStratergy rs = (RoundingStratergy)   Type.forName(selectedRoundingStratergy.ClassNamespacePrefix,

    selectedRoundingStratergy.ClassName).newInstance();

       

Decimal rounded = rs.round(7.1459);

System.assertEquals(7.15, rounded);


 

Use the new getSObjectType()

 

Use the new getSObjectType() method to get the SObjectType of a Schema.DescribeFieldResult object. The returned type is that of the source sObject describe object that was originally retrieved, eliminating the need for additional mechanisms to determine parent relationships.

 

This example uses the getSObjectType() method to create a Salesforce object of the same type as the passed in field’s originating object and then dynamically populates the field’s value.

public class ObjectCreator {
 
    public static sObject createAndSet(Schema.sObjectField field, object fieldValue) {
        Schema.DescribeFieldResult fieldDescribe = field.getDescribe();
        Schema.sObjectType sourceType = fieldDescribe.getSObjectType();  
        sObject newObj = sourceType.newSObject(null, true);
        newObj.put(field, fieldValue);
        return newObj;
    }
}

Here’s how to call the sample createAndSet() method.

sObject o = ObjectCreator.createAndSet(Account.Industry, 'Development');
Assert.isInstanceOfType(o, Account.class);
Assert.areEqual('Development', ((Account)o).Industry);

 

 

 

LWC

 

Improved Conditional Directives

The lwc:iflwc:elseif, and lwc:else conditional directives supersede the legacy if:true and if:else directives.

 

Previously, chaining if:true and if:false blocks introduced performance cost and resulted in the property getters getting called multiple times.

<!-- legacyConditional.html -->
<template>
    <!---Replace if:true with lwc:if-->
    <template if:true={isTemplateOne}> 
        This is template one.
    </template>
    <!-- Replace if:false with lwc:else -->
    <template if:false={isTemplateOne}> 
        This is template two.
    </template>
</template>

 

Update

With the lwc:iflwc:elseif, and lwc:else conditional directives, the property getters are accessed only one time per instance of the directive.

<!-- conditionalExample.html -->
<template>
    <template lwc:if={isTemplateOne}>
        This is template one.
    </template>
    <template lwc:else>
        This is template two.
</template>

Both lwc:elseif and lwc:else must be immediately preceded by a sibling lwc:if or lwc:elseif.

Pass in an expression to lwc:if and lwc:elseif, but not to lwc:else.

If expression1 returns a truthy, none of the other property getters are accessed.

<!-- example.html -->
<template>
    <template lwc:if={expression1}>
        Statement 1
    </template>
    <template lwc:elseif={expression2}>
        Statement 2
    </template>
    <template lwc:else>
        Statement 3
    </template>
</template>

 

 

 

 

 

 


 

 

 

Reference Link