Clone Opportunity with Products action on Opportunities ( Lightning Component )

I am following this idea since I needed this feature in one of my projects. Since Salesforce already has this in their future roadmap, I realized that It could be an addition to my #GivingBackToCommunity list. I managed to create a lightning component which can be used with lightning action on Opportunity records. This will allow users to clone an opportunity with the products.

IdeaExchange Idea

Here is the idea on the IdeaExchange

clone with products

Lightning Component for Clone with Products

Here is the link to the Lightning Component GitHub repository
clone with products

 

Steps to Install/Configure this component in your Org

For Sandbox/Dev Environment

First, you need to identify whether you want to install a managed or unmanaged package. This can be determined based on your purpose. If you want to amend existing functionality then the unmanaged package is what you are looking for. If that’s not the case and you just want to test it before installing it to the production then managed package is your best bet.

  1. Install the package in your Org. Following are the links to the package installation URL.
    Link to unmanaged package
    Link to managed package
  2. After installing package successfully, you need to configure it and you will have to switch to Salesforce classic view as you need to update the fieldsets ( fieldsets are not available in lightning experience till Winter ‘2018 release).
  3. You have 2 fieldsets first one on Opportunity object and the second one on the OpportunityProduct object. These fieldsets let you decide which field values you want to copy to new opportunity ( cloned opportunity ). By default, it will copy those fields only which are required to save the record.
  4. To modify the fieldset fields navigate to Setup | Customize | Opportunity | FieldSets and you will find the Clone Opportunity Field Set.
  5. You can add fields which you want to be copied in the new opportunity. See the below screenshot.
  6. After adding the fields in the fieldset, you need to add action to the page layout. So navigate to the page layout section and drag the “Clone with Products” action on the pane.
  7. Save everything and switch back to lightning experience view to use this feature.
Screenshot_9
Clone Opportunity Field Set

 

Screenshot_10
Lightning action in page layout

 

For Production Environment

  1. Install the package in your Org. Following are the links to the package installation URL.
    Link to managed package

Rest steps are same as explained for the sandbox environment.

Please let me know if you have any feedback on this.

 

How to create table with resizable columns using Lightning Design System ( Column Resizable DataTable )

Lightning design system comes with some really nice cascading stylesheet but still, there are some components where JS support is not provided. During a project, I came across the same where I had to write Javascript code by myself. After going many rounds of testing and changes, finally, I managed to get it working. It’s Data Table component which I am talking about.

How does the column resizing work?

I have used mousedown and mousemove events to recognize the mouse cursor moment. Resizable columns have a divider which let users change the column width. You can check the following Gist for the code.

LINK TO SAMPLE CODE

Table

Please feel free to comment your question/suggestions in the comment box.

Salesforce Cookies #12

How to remove the arrows from lightning:input[type=”number”]?

I think this is a generic question and Salesforce devs have looked for the ways to get rid of the spin buttons on the input field without changing it to text type for a purely numeric behaviour. You just need a few lines of CSS to solve your problem.

We need some CSS which work across the browsers. Any browser like Safari, Chrome and Firefox have a specific bahaviour for number type inputs.

Component.css

In the CSS component of the Lightning component bundle, we need to include the following styling.

/* For Firefox browser */
.THIS input[type='number'] {  
   -moz-appearance:textfield;
}
/* For webkit browsers like Chrome and Safari */
.THIS input[type=number]::-webkit-inner-spin-button,
.THIS input[type=number]::-webkit-outer-spin-button {
   -webkit-appearance: none;
   margin: 0;
}

So it will look like as shown here.

Screenshot_2     Screenshot_1

In case if you have any concern or queries then please feel free to comment on the post.

Have fun with the CSS!!

Salesforce Cookies #10

Creating a dynamic SOQL which includes all the fields

I have seen this question several times on developer forums and I thought it could be another addition to Salesforce cookies. If you are wondering how can you query all the fields of an object then you can use the following code snippet.

The above code snippet using describe calls to get all the fields and then created a dynamic SOQL query to get all the field values.

This is quite similar to SQL query which uses wildcard characters – SELECT * FROM Table.

Salesforce Cookies #9

Populating merge fields in Salesforce Email Template without sending the email / Preview Email Template

Recently, I faced a challenge while working on a small project in which I had to send email through apex using email templates. I am calling it a challenge because of the problem I faced and I am sharing the solution/workaround I found for this.

Problem – The Email template was using custom fields of the Campaign Member object and whenever I was sending email to Campaign Member ( Lead ), those custom fields were not populating. I tried to set the WhatId to CampaignMember record Id but were getting an error in Messaging.sendEmail method. Unfortunately, I couldn’t use workflow/process builder as email’s from address had to be dynamically set based on some criteria.

Solution –  Used the renderEmailTemplate method of Messaging class and then set the merged body of the result as HtmlBody of the SingleEmailMessage object. Here didn’t get any error when I passed the campaign member record id as whatId.

Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String htmlBody = '';
EmailTemplate et = [SELECT Id, Subject, HtmlValue FROM EmailTemplate Where DeveloperName = 'Sample_Email_Template'];
email = Messaging.renderStoredEmailTemplate(et.Id, cm.LeadId, cm.Id);
mail.setTargetObjectId( cm.LeadId );
mail.setOrgWideEmailAddressId( orgWideEmailAddressId );
mail.setSaveAsActivity(false);

The above-mentioned approach can be used in many scenarios like

  1. If you want to preview Email Template content after populating all the merge field values.
  2. Where you can’t set the WhatId of the record directly for SingleEmailMessage object to render merge fields which are used in the email template.
  3. You want to send email to the user and can’t set the TargetObjectId field of the SingleEmailMessage object along with WhatId.
  4. Messaging.renderStoredEmailTemplate method takes 3 parameters, email template Id is the required one.

There are other variants of this method in Messaging class which you can found useful in your use case. You can get the rendered merge field with the help of GetHtmlBody() method of the SingleEmailMessage class from the returned object.

Resource –

Messaging Class

 

Salesforce Cookies #8

How to use namespace in managed lightning components

If you are working on a lightning component and it’s going to be a part of a managed package then you need to take care of namespace in client side JS code if you are accessing any custom field. This can be handled in various ways but I found one very quick way to handle this. Using wrapper could be a best way but it’s time consuming so you can use the following way.

Get the namesapce from server side controller and use that in the lightning components.

NamespaceDemoComp.cmp

NamespaceDemoCompController.cls

NamespaceDemoCompController.js

NamespaceDemoCompHelper.js

So, you can see in the above example that using namespace in JS code can save lot of time as compared to wrapper classes. Expense__c is a custom object and this code will take care of the namespace automatically based on the running environment. If there is a namespace then it will be added as suffix with field’s API names in JS code.

Happy coding 🙂

Salesforce Cookies #7

Untitled

Calling a child lightning component method from the parent lightning component

When we have multiple nested components then we may run into a scenario in which our parent lightning component is supposed to call a method of its child component. This is a very common use case.


simplifies the code needed for a parent component to call a method on a child component that it contains

The lightning component framework has  which simplifies the code needed for a parent component to call a method on a child component that it contains. Following example states pretty everything you want to know about it.

Declare the method defination and it’s parameters in child component as explained below.

<aura:method name="handleShowHidePopupEvent" action="{!c.handleShowHidePopupEventAction}" description="Method to show or hide the popup from a button on the parent component">
    <aura:attribute name="showPopup" type="Boolean" default="true"/>
</aura:method>

Create a handler method in the client side controller of the same child component

({
   handleShowHidePopupEventAction : function(cmp, event) {
     var params = event.getParam('arguments');
     if (params) {
       var showPopup = params.showPopup;
       if(showPopup) {
         var cmpTarget = cmp.find('popupParentDiv');
         $A.util.removeClass(cmpTarget, 'slds-hide');
       } else {
         var cmpTarget = cmp.find('popupParentDiv');
         $A.util.addClass(cmpTarget, 'slds-hide');
       }
     }
   }
})

Above code snippet is toggling a parent div of the popup (model). You can also write any specific logic here which you just want to have in the child component only.

Calling method from the parent component – To close the popup after executing the save button logic or cancel button logic

<c:editRecordComponent aura:id="editRecordCmp"/>
<button class="slds-button" type="button" onclick="{!c.saveRecord}"> Save & Close </button>
<button class="slds-button" type="button" onclick="{!c.cancel}"> Cancel </button></pre>

Method in parent component controller

({
  cancel : function(cmp, helper, event){

    var editRecordCmp = component.find("editRecordCmp");
    editRecordCmp.handleShowHidePopupEvent( false );
  }
})

can also return a value once the execution has been completed.

To read more about, please check aura:method in Lightning Components Developer Guide.

Happy coding 🙂

Salesforce Cookies #6

Adding Loading Icon on the page for an AJAX Request ( ActionFunction, CommandButton)

It’s always good to add a loading icon on the page when you are processing something on the server side (calling an apex method ) so a user can understand that something is running in the background. Following code snippet can be used along with your apex:actionFunction or apex:commandButton.

In Classic

<apex:actionStatus id="actionStatus">
  <apex:facet name="start" >
    <img src="/img/loading.gif" />
  </apex:facet>
</apex:actionStatus>

In Lightning Experience

<apex:actionStatus id="actionStatus">
  <apex:facet name="start" >
    <div class="slds-spinner_container">
      <div class="slds-spinner--brand slds-spinner slds-spinner--small" aria-hidden="false" role="alert">
        <div class="slds-spinner__dot-a"></div>
        <div class="slds-spinner__dot-b"></div>
      </div>
    </div>
  </apex:facet>
</apex:actionStatus>

Using ActionStatus in CommandButton

<apex:commandButton value="Save" action="{!Save}" status="actionStatus"/>

Happy Coding 🙂

Salesforce Cookies#5

Uploading Attachment from Non-Salesforce Users ( Site or Guest Users) through Force.com sites

I came across a question on Trailblazers community where someone asked for a way to upload an attachment to a record and it should be accessible by non-salesforce users. I won’t go into much detail about that and will focus on providing the solution.

So, you just have to follow the below-mentioned steps to make it work for you.

  1. Setup a Force.com site if you haven’t already. You can get more details about this from this link.
  2. Create a VF page which lets an external user upload an attachment to Salesforce record.
  3. Add the page ( created in 2nd step) to the Site created in 1st step. Find more details here.

Visualforce page for Upload Attachment

You just need a VF page and here is the code gist which you can utilize and update as per your need.

Upload Attachment through Force.com sites

Happy coding 🙂

 

Salesforce Cookies #4

Never store record’s Id as a String (Variable type) if you are comparing Ids in your Apex code

If you are writing apex code then make sure that you are treating Ids’ carefully.  You should emphasize on declaring your variables of Id-type instead of String since storing record Id in a variable which type is Id will do the 15-character Id to 18-character Id conversion. Let’s take an example.

Code uses String type variable for holding record Ids
Map<String, Opportunity> mapOpportunities = new Map<String, Opportunity>();
mapOpportunities.put('006w000000tVvtt', Opp);
006w000000tVvtt - 15_Character_Opp_Id  

String oppRecordId = '006w000000tVvttAAG';
mapOpportunities.containsKey( oppRecordId ); // Will return False
006w000000tVvttAAG - 18_Character_Opp_Id

// Same as above 
String character_15_id = '006w000000tVvtt';
String character_18_id = '006w000000tVvttAAG';
character_15_id == character_18_id  // return false
Code uses Id type variable for holding record Ids
Map<Id, Opportunity> mapOpportunities = new Map<Id, Opportunity>();
mapOpportunities.put('006w000000tVvtt', Opp);
006w000000tVvtt - 15_Character_Opp_Id  
Id oppRecordId = '006w000000tVvttAAG';
// Performing containsKey operation will give you true 
// since declaring the map key as Id has done the required ID's conversion
mapOpportunities.containsKey( oppRecordId ); // Will return True
006w000000tVvttAAG - 18_Character_Opp_Id

// Same as above 
Id character_15_id = '006w000000tVvtt';
Id character_18_id = '006w000000tVvttAAG';
character_15_id == character_18_id // return true

Declaring such variables as Id will also help you to deal with invalid Ids. Happy coding!! 🙂