Saturday, 7 September 2019

How to restrict your component to one or more objects?

Hi ,

We can restrict to our component to one or more objects by using the following:

<sfdc:objects> and <sfdc:object>

Here in the following example we are restricting the component to Opportunity which is using the following design component by using  <sfdc:objects> and <sfdc:object>.


<design:component label="Hello World">
    <design:attribute name="subject" label="Subject"/>
    <design:attribute name="greeting" label="Greeting" />    
    <sfdc:objects>       
        <sfdc:object>Opportunity</sfdc:object>
    </sfdc:objects>
</design:component>

If we define the design component with lightning component as above then it will be available for Opportunity Lightning Record page only.

Reference:

Sunday, 18 August 2019

Test Class for Call back class which implements Metadata.DeployCallback interface

Hi,

When we create a class to insert metadata using Metadata class then we write callback class to send notifications or another process about the status of deployment or insert of metadata.

 Callback class:
public class PostInstallCallback implements Metadata.DeployCallback{
public void handleResult(Metadata.DeployResult result,
        Metadata.DeployCallbackContext context) {
       
        if (result.status == Metadata.DeployStatus.Succeeded) {
            // Deployment was successful, take appropriate action.     
           Messaging.SingleEmailMessage  msgObj = new Messaging.SingleEmailMessage ();
            msgObj.setSubject('MetaData insertion succeeded');         
            List<String> emailAddresses = new List<String>{UserInfo.getUserEmail()};
            Metadata.DeployDetails deployDetailsList = result.details;
            List<Metadata.DeployMessage> deploymentMessagesList = deployDetailsList.componentSuccesses;   
            String errorMessageBody = '';
            for(Metadata.DeployMessage messageObj:deploymentMessagesList){
                if(messageObj.success==true && !String.valueOf(messageObj.fullName).split('\\.')[1].containsIgnoreCase('xml')){
                    errorMessageBody+=String.valueOf(messageObj.fullName).split('\\.')[1]+'\n';
                }
            }
            errorMessageBody +=' records created';
            msgObj.setPlainTextBody(errorMessageBody);
            msgObj.setToAddresses(emailAddresses);
            Messaging.sendEmail(new List<Messaging.Email>{msgObj});         
        } else {
            // Deployment wasn’t successful, take appropriate action.
            Messaging.SingleEmailMessage  msgObj = new Messaging.SingleEmailMessage ();
            msgObj.setSubject('MetaData insertion failed');
            msgObj.setPlainTextBody(result.details+'='+result.errorMessage);
            List<String> emailAddresses = new List<String>{UserInfo.getUserEmail()};     
            Metadata.DeployDetails deployDetailsList = result.details;
            List<Metadata.DeployMessage> deploymentMessagesList = deployDetailsList.componentFailures;   
            String errorMessageBody = '';
            for(Metadata.DeployMessage messageObj:deploymentMessagesList){
                if(messageObj.success==false){
                    errorMessageBody+=messageObj.problem+'\n';
                }
            }
            msgObj.setPlainTextBody(errorMessageBody);
            msgObj.setToAddresses(emailAddresses);
            Messaging.sendEmail(new List<Messaging.Email>{msgObj});
        }
    }
}


Test Class:

@isTest
private class PostInstallCallbackTest {
@IsTest
    static void testMyCallback() {
       
        // Instantiate the callback.
        Metadata.DeployCallback callback = new PostInstallCallback();     
        // Create test result and context objects.
        Metadata.DeployResult result = new Metadata.DeployResult();
        result.status = Metadata.DeployStatus.Succeeded;
        Metadata.DeployMessage messageObj = new Metadata.DeployMessage();
        messageObj.changed = true;
        messageObj.success = true;
        messageObj.fullName='';
        messageObj.componentType ='CustomMetadata';
        messageObj.fullName = 'VAT_Rate.SreeVardhan3';
        Metadata.DeployDetails deployDetailsObj = new Metadata.DeployDetails();
        deployDetailsObj.componentSuccesses.add(messageObj);
        result.details = deployDetailsObj;     
        Metadata.DeployCallbackContext context = new Metadata.DeployCallbackContext();
       
        // Invoke the callback's handleResult method.
        callback.handleResult(result, context);
    }
    @IsTest
    static void testMyCallbackErrorMessage() {
       
        // Instantiate the callback.
        Metadata.DeployCallback callback = new PostInstallCallback();     
         // Create test result and context objects.
        Metadata.DeployResult result = new Metadata.DeployResult();
        result.status = Metadata.DeployStatus.Failed;
        Metadata.DeployMessage messageObj = new Metadata.DeployMessage();
        messageObj.changed = false;
        messageObj.success = false;   
        messageObj.componentType ='CustomMetadata';
        messageObj.fullName = 'VAT_Rate.SreeVardhan3';
        messageOBj.problem = 'Default: value not of required type: 1';
        messageObj.problemType = Metadata.DeployProblemType.Error;
        Metadata.DeployDetails deployDetailsObj = new Metadata.DeployDetails();
        deployDetailsObj.componentFailures.add(messageObj);
        result.details = deployDetailsObj;     
        Metadata.DeployCallbackContext context = new Metadata.DeployCallbackContext();       
        // Invoke the callback's handleResult method.
        callback.handleResult(result, context);
    }
}


References:
https://trailhead.salesforce.com/en/content/learn/modules/apex_metadata_api/apex_metadata_api_testing

Monday, 29 July 2019

The SOQL Count() Function Doesn’t Count (As Much) Toward Limits

Hi,

Previously, each individual record matched by the SOQL COUNT() and COUNT(fieldName) functions counted toward the query row limit. So requesting a count could have a significant impact on governor limits, especially when working with many records. Now, if a query using one of these functions returns an integer, it only counts as one query row toward the governor limit. If a query using one of these functions returns an array of AggregateResult objects, only the total number of AggregateResult objects counts toward the limit.

For example, consider the following query.
Integer countOfContacts = [SELECT COUNT() FROM Contact WHERE Account.Name = 'Edge Communications'];
Previously, the number of records matched by this query counted toward the limit. Now this query counts as only one query row toward the limit.
The following query uses the COUNT(fieldName) function. Previously, the number of rows returned counted toward the limit, but now this query counts as a single query row.
AggregateResult ar = [SELECT COUNT(AccountId) rowcount FROM Contact]; // Count contacts with an account only
Integer rowCount = (Integer)ar.get('rowcount');
If a query that uses the COUNT(fieldName) function contains a GROUP BY clause, only the number of resulting AggregateResult objects count toward the limit. For example, in the query in the following example, only one item per aggregated result is counted toward the limit.
List<AggregateResult> res = [SELECT COUNT(id) FROM Contact GROUP BY AccountId];
System.assertEquals(res.size(), Limits.getQueryRows());
Previously, all the records matched by this query counted toward the query row limit.


Reference:

Sunday, 30 June 2019

Load or Update Records with the Custom Metadata Loader

Hi,
Usually, we can't insert or update Custom Metadata records using Apex with normal DML statements.

We have custom meta loader to insert or update multiple records into Custom Metadata.


The custom metadata loader lets you load or update up to 200 records with a single call.

  1. Download the tool from GitHub and deploy the package to your org via Workbench. Create the .zip file from the contents of the custom_md_loader directory instead of zipping up the directory itself.
  2. Create a .csv file with a header that contains the custom metadata type’s field API names. Either the Label or the Developer Name field is required. See sample.csv in your download for an example. If your org is namespaced, include the namespace prefix in your header. To update an existing custom metadata record, use the Label or Developer Name field to identify it.
  3. From Setup, assign the Custom Metadata Loader permission set to the appropriate users, including yourself.
  4. From the App Picker, select Custom Metadata Loader.
  5. Click the Custom Metadata Loader tab. If you haven’t already done so, the app prompts you to configure your Remote Site Settings.
  6. Upload your .csv file and select the corresponding custom metadata type.
  7. Click Create/Update custom metadata to bulk-load the records from the .csv file or update existing records. If the file has duplicate Label or Developer Name entries, the last entry becomes the new or updated record.


References:

Saturday, 22 June 2019

Custom Metadata Record creation in apex

Hi,

Here I am going to explain how can we create custom metadata record in apex.

Usually, we can' create custom metadata record through DML statements in apex.


But we have  "Metadata" class to create Custom Metadata record in apex.

When we use this no DML operations happen for creating records. instead, it does the deployment of custom metadata values.

Whenever we want to use this we have to create a call back class which implements "Metadata.DeployCallback" interface as shown below as this action is asynchronous.

Callback Class:
public class MetadataCallbackCls implements Metadata.DeployCallback {
    public void handleResult(Metadata.DeployResult result,
                             Metadata.DeployCallbackContext context) {
        if (result.status == Metadata.DeployStatus.Succeeded) {
            System.debug('success: '+ result);
        } else {         
            System.debug('fail: '+ result);
        }
    }
}


Example Snippet for creating Custom Meta Data:


Let's take custom metadata type "User_Creds__mdt" which has a custom field "Password__c".

To insert a record into the same we have to follow the same below.

    Metadata.CustomMetadata customMetadataObj =  new Metadata.CustomMetadata();
    customMetadataObj .fullName = 'User_Creds__mdt.Balaji_M';
    customMetadataObj .label = 'Balaji_M';

    Metadata.CustomMetadataValue customFieldObj = new Metadata.CustomMetadataValue();
    customFieldObj .field = 'Password__c';
    customFieldObj .value = 'XXXXX';

    customMetadataObj.values.add(customFieldObj);

    Metadata.DeployContainer containerObj= new Metadata.DeployContainer();
    containerObj.addMetadata(customMetadataObj);


    MetadataCallbackCls  callback = new MetadataCallbackCls ();
 
    Id jobId = Metadata.Operations.enqueueDeployment(containerObj, callback);


Output:




References:

https://developer.salesforce.com/docs/atlas.en-us.208.0.apexcode.meta/apexcode/apex_class_Metadata_CustomMetadata.htm#apex_class_Metadata_CustomMetadata


https://trailhead.salesforce.com/en/content/learn/modules/apex_metadata_api/apex_metadata_api_updates

https://trailhead.salesforce.com/en/content/learn/modules/custom_metadata_types_adv/cmt_develop

https://developer.salesforce.com/docs/atlas.en-us.208.0.apexcode.meta/apexcode/apex_interface_Metadata_DeployCallback.htm#apex_Metadata_DeployCallback_methods

Sunday, 5 May 2019

What is Lightning Web Component

Hi ,

I just want to give you small information about Lightning Web Component.

We can build Lightning components using two programming models:


  1. Original model, Aura Components
  2. Lightning Web Components

Lightning web components are custom HTML elements built using HTML and modern JavaScript. 
Lightning web components and Aura components can coexist and interoperate on a page.

To admins and end users, they both appear as Lightning components.

References:

Configure Default Field Values with Custom Metadata Types

Hi ,

Now with Spring 19 we can configure default field values with custom metadata types.
While creating fields you can defined the default value using formula expression. In formula expression you may not able to see the  record name with field from meta data type.

But you can following syntax to include one metadata record field value. 

$CustomMetadata.CustomMetadataTypeAPIName.RecordAPIName.FieldAPIName

Eg:

$CustomMetadata.DiscountPercent__mdt.IT.discount__c

Here
DiscountPercent__mdt - API name of the metadata type

IT - is API Name of the record in the metadata type

Discount__C- is  Field API Name of the metadata type where we configure discount value.


By using this you can avoid updating the data references when there is any default value change in future instead you just need to change in one location which reflects all references.


Sunday, 20 January 2019

Create Dynamic Picklists for Your Custom Components (design:component)

Hi,


We can expose a component property as a picklist when the component is configured in the Lightning App Builder. The picklist’s values are provided by an Apex class that you create.

For example, let’s say you’re creating a component for the Home page to display an object records. You can use an Apex class to put the object Names of your Salesforce org in a picklist in the component’s properties in the Lightning App Builder. Then, when admins add the component to a Home page, they can easily select the appropriate object to display records on the page.

Usually we use <design:component/> to set default values for a component while adding it in App Builder. When we want to provide picklist to hold all objects for selection while adding we have to follow the things below.

  • Create a custom Apex class to use as a datasource for the picklist. The Apex class must extend the VisualEditor.DynamicPickList abstract class.
  • Add an attribute to your design file that specifies your custom Apex class as the datasource.
Apex Class

global class MyCustomPickList extends VisualEditor.DynamicPickList{
    
    global override VisualEditor.DataRow getDefaultValue(){
        VisualEditor.DataRow defaultValue = new VisualEditor.DataRow('account', 'Account');
        return defaultValue;
    }
    global override VisualEditor.DynamicPickListRows getValues() {        
        VisualEditor.DynamicPickListRows  picklistRowsList = new VisualEditor.DynamicPickListRows();
        List<VisualEditor.DataRow> dataRowsList = new List<VisualEditor.DataRow>();
        for(Schema.SObjectType sobjectTypeName:schema.getGlobalDescribe().values()){
            VisualEditor.DataRow rowObj = new VisualEditor.DataRow(sobjectTypeName.getDescribe().getLabel(), sobjectTypeName.getDescribe().getName());
            dataRowsList.add(rowObj);
           
        }
         picklistRowsList.addAllRows(dataRowsList);      
       
        return picklistRowsList;
    }
}

Add the Apex Class to Your Design File
To specify an Apex class as a datasource in an existing component, add the datasource

<design:component>
        <design:attribute name="sobjectName" datasource="apex://MyCustomPickList"/>
</design:component>


Dynamic Picklist Considerations

  • Specifying the Apex datasource as public isn’t respected in managed packages. If an Apex class is public and part of a managed package, it can be used as a datasource for custom components in the subscriber org.
  • Profile access on the Apex class isn’t respected when the Apex class is used as a datasource. If an admin’s profile doesn’t have access to the Apex class but does have access to the custom component, the admin sees values provided by the Apex class on the component in the Lightning App Builder.
References:
https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/components_config_for_app_builder_dynamic_picklists.htm#components_config_for_app_builder_dynamic_picklists

Saturday, 8 December 2018

Convert 15 character IDs to 18 character IDs in formula field

Hi ,

We have new method "CASESAFEID()"in formula field now to make 15 character Id to 18 character.

Classic
1. Go to Setup | Customize | object name | click Fields
a. For Custom objects: Setup Create Objects | object name
3. In the related list "Custom Fields & Relationships" click New.
4. Click the Formula radio button.
5. Click the Text radio button for 'Formula Return Type.'
6. Input the following Formula into the Formula Editor:
CASESAFEID(Id)

7. Set Field Visibility, add or remove from the page layout.
 8. Click Save.

Lightning
 
1. Go to Setup Object Manager | Object name | Fields & Relationships
2. Click New.
3. Click the Formula radio button.
4. Click the Text radio button for 'Formula Return Type.'
5. Input the following formula into the Formula Editor:
CASESAFEID(Id)

6. Set Field Visibility, add or remove from the page layout.
7. Click Save.


Reference:
https://help.salesforce.com/articleView?id=000005288&language=en_US&type=1

Sunday, 25 November 2018

Run Script After Sandbox Creation and Refresh

Hi ,
We have an interface SandboxPostCopy from salesforce.com to do data manipulation after sandbox is created or refresh.
It makes our  sandbox environment business ready, automate data manipulation or business logic tasks.
At sandbox creation, specify a single Apex class to perform the tasks. This class executes every time the sandbox is copied.
Lightning interface of sandbox post-copy script specification

Create an Apex class that implements SandboxPostCopy and specify the class here. For example, the following Apex class simply reports the three contexts available in SandboxPostCopy: your organization ID, sandbox ID, and sandbox name:
Example:
global class HelloWorld implements SandboxPostCopy {
  global void runApexClass(SandboxContext context) {
      System.debug('Hello Tester Pester ' + context.organizationId()
           + ' ' + context.sandboxId() + context.sandboxName()); 
    }
  }

you can write your business logic in the method "runApexClass"

Reference:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_interface_System_SandboxPostCopy.htm?search_text=SandboxPostCopy#apex_interface_System_SandboxPostCopy_Example
https://docs.releasenotes.salesforce.com/en-us/spring16/release-notes/rn_deployment_sandbox_postcopy_script.htm





Monday, 19 November 2018

SFDX with Non Scratch Orgs

Hi ,

Gave demo on SFDX with Non Scratch orgs in our Salesforce Techbook Channel. You can learn how to use SFDX with Non Scratch orgs after this demo.





References:

https://trailhead.salesforce.com/en/content/learn/trails/sfdx_get_started
SFDX CLI:https://developer.salesforce.com/tools/sfdxcli
VS Code:https://code.visualstudio.com/download
Salesforce Extensions:
https://marketplace.visualstudio.com/items?itemName=salesforce.salesforcedx-vscode






How to restrict your component to one or more objects?

Hi , We can restrict to our component to one or more objects by using the following: <sfdc:objects>  and  <sfdc:object> H...