Sep 14, 2016

Winter 17 sneak peak - Lightning Lovers

Winter 17 is here and we all are excited about it!

Here are some new features which I like when I took a glimpse on release notes.

-> Lightning navigation Menu is changed from vertical to Horizontal.




 
-> All custom apps created in classic view will be supported. But now their description is also available so we might need to add description in missing apps so that they look good and this is an optional step.


-> After your users create, edit, or clone a record in Lightning Experience, they can create another record using the Save & New button. The Save & New button lets users create records repeatedly without leaving their spot in the app.

-> Field Level help is now available in Lex and SF1


-> You can no take ownership of multiple lead at once. From the queue list view, your reps can select all the leads (up to 200). When they click Accept, they’re committed and those leads become theirs. 

->  Global picklist now available in Lightning experience and we can now send them with change set from Sandbox to production.
-> Now the Open CTI is available in Lex. In the bottom you can access the CTI.

-> Your code can use merge fields to construct the bodies of Apex callouts to named credential–defined endpoints. Those merge fields now support the HTMLENCODE function so you can escape special characters, such as underscore (_) and ampersand (&), in the merge fields in callout bodies.
HTMLENCODE is an existing formula function. Other formula functions aren’t supported, and you can’t use HTMLENCODE on merge fields in HTTP headers.

Example

The following example escapes special characters in credentials.
req.setBody('UserName:{!HTMLENCODE($Credential.Username)}')
req.setBody('Password:{!HTMLENCODE($Credential.Password)}')

-> Record Details Tab Never Forgets in Lightning Experience

When your users expand or collapse a section in record details in Lightning Experience, the section stays that way even after visiting other areas in Salesforce. This change helps users scroll through a record faster, showing only the information they care about.
For example, in Lead details, a user collapses the Address Information section and expands the Additional Information section. The next time the user views a lead’s details with the same layout, those sections remain collapsed and expanded, respectively.




-> Confirmation messages that appear after your users create, edit, delete, or clone a record successfully from a related list in Lightning Experience and Salesforce1 have changed. The messages include the record name for more context. Also, after your users create a record from a related list in Lightning Experience (not Salesforce1), the popup message includes a link to the record for easy navigation.

-> Navigate from a Lightning Component to Another (Beta)

To navigate from a Lightning component to another, specify the component name using componentDef. This example navigates to a component c:myComponent and sets a value on the contactName attribute.


navigateToMyComponent : function(component, event, helper) { varevt = $A.get("e.force:navigateToComponent"); evt.setParams({ componentDef : "c:myComponent", componentAttributes: { contactName :component.get("v.contact.Name")             }         }); evt.fire();     }

-> Opportunity owner can edit the probability of the opportunity without switching in the Salesforce Classic view.

-> The time window to quick-deploy your validations has expanded from 4 days to 10 days.

-> Apex test suites are now accessible through the Metadata API, using the ApexTestSuite type. You no longer need to recreate test suites in each of your testing orgs. Instead, create an Apex test suite once and deploy it and its test classes to each of your test environments. Now you can focus on more important things, like whether to call your new test methodwhatTheHeckIsWrongHere() or pleasePleasePleaseReturnTrue().

If there are any which you like the most, please list them as comment.

Happy Winter 17!

Sep 6, 2016

Lightning experience OR classic view, where am I?

Have you ever faced a problem of identifying in which experience user is opening your page (VFP)? Is it lightning or classic.



Well, here is the solution to it. There are two ways :

1) Via Apex

public boolean isLightningExperience()
{
 if(Apexpages.currentPage().getParameters().get('sfdcIFrameOrigin') != null)
        return true;
 return false;
}

2) Via JS on visualforce page

function isLightningExperience()
{
  if('{!$Currentpage.parameters.sfdcIFrameOrigin}' != '')
  return true;
  return false;
}

You can use two parameters to check this 'sfdcIFrameOrigin' and 'istdp'. Now you can easily identify in which experience the user is via your code and can manipulate the functionality accordingly. 

Happy Coding!!

Aug 30, 2016

Dynamic nth Level Hierarchy in Salesforce

This blog is somewhat related to my previous post but with bit easy implementation and more generic. We have encountered this implementation multiple time so thought of sharing it with all.

Ever thought of replicating this feature in any of your custom object?


Now the only complication is, in case of self lookup you don't know the end node and where your loop should stop (to think about the logic). So hope I will make it easy for you.

*Note : My blog code formatter is not working properly, so please check the spaces before using the code.

Step 1 : Create an apex class called HierarchyController, as shown below and save it.

public with sharing class DynamicHierarchyForBlogController 
{
 public String objectApiName {get;set;}
 public String fieldApiName {get;set;}
 public String nameField {get;set;}
 public String currentsObjectId {get;set;}
 public String topParentId {get;set;}
 public String jsonMapsObjectString {get;set;}
 private String jsonString;
 private Map> sObjectIdMap ;
 private Map selectedsObjectMap ;
 private Map allsObjectMap;

 public DynamicHierarchyForBlogController() 
 {
  currentsObjectId = Apexpages.currentPage().getParameters().get('id');
     sObjectIdMap = new Map>();
  selectedsObjectMap = new Map();
  allsObjectMap = new Map();
 }
 
 public String getjsonMapString()
 {
  retrieveInfo();
  return jsonString;
 }
 
 public void retrieveInfo()
 {
  String dynamicQuery = 'SELECT ID ,' + fieldApiName + ' , ' + nameField + ' FROM ' + objectApiName + ' ORDER BY ' + fieldApiName + '  LIMIT 50000';
  for(sObject obj: Database.query(dynamicQuery))
  {
   allsObjectMap.put(obj.id,obj);
  }

  if(currentsObjectId != null)
  {
   String dQuery = 'SELECT ID FROM ' + objectApiName + ' WHERE id =\'' + currentsObjectId +'\'';
   List objList = Database.query(dQuery);
   currentsObjectId = objList[0].Id;
   retrieveTopParent(currentsObjectId);
   retrieveAllChildRecords(new Set{topParentId});
   for(String str : sObjectIdMap.keySet())
   {
    selectedsObjectMap.put(str,allsObjectMap.get(str));
   }
   jsonString = JSON.serialize(sObjectIdMap);
   jsonMapsObjectString = JSON.serialize(selectedsObjectMap);
  }
 }

 public void retrieveTopParent(String sObjectId)
 {
  if(allsObjectMap.keySet().contains(sObjectId) && allsObjectMap.get(sObjectId).get(fieldApiName) != null)
  {
   topParentId = String.valueOf(allsObjectMap.get(sObjectId).get(fieldApiName));
   retrieveTopParent(topParentId);
  }
 }

 public void retrieveAllChildRecords(Set sObjectIdSet)
 {
  if(sObjectIdSet.size() > 0)
  { 
   Set allChildsIdSet = new Set();
   for(String str : sObjectIdSet)
   {
    Set childsObjectIdSet = new Set();
    for(sObject obj : allsObjectMap.values())
    {
     if(obj.get(fieldApiName) != null && String.valueOf(obj.get(fieldApiName)) == str)
     {
      childsObjectIdSet.add(obj.Id);
      allChildsIdSet.add(obj.Id);
     }
    }
    sObjectIdMap.put(str,childsObjectIdSet);
   }
   retrieveAllChildRecords(allChildsIdSet);
  }
 }
}

Step 2 : Now create a component called Hierarchy, as shown below and save it.

<apex:component controller="DynamicHierarchyForBlogController">
 
 <apex:attribute name="objectName" description="Name of Object." type="String" required="true" assignTo="{!objectApiName}"/>
 <apex:attribute name="FieldName" description="Name of the field of the object." type="String" required="true" assignTo="{!fieldApiName}"/>
 <apex:attribute name="RepersenterField" description="Name field of the object." type="String" required="true" assignTo="{!nameField}"/>
 <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
 
 <div id="parentDiv"></div>
 
    <style>
     #parentDiv ul:first-child
     {
      padding: 0;
     }
     #parentDiv li
     {
      list-style: none;
      padding: 10px 5px 0 5px;
      position: relative;
     }
  #parentDiv li span 
  {
      -moz-border-radius: 5px;
      -webkit-border-radius: 5px;
      /*border: 1px solid #999;*/
      border-radius: 5px;
      display: inline-block;
      padding: 3px 8px;
      cursor: pointer;
  }
  .selectedRecord
  {
   font-weight:bold; 
   color:blue;
  }
    </style>
    <script>
      var accountMap = JSON.parse('{!jsonMapString}');
      var accountValueMap = JSON.parse('{!jsonMapsobjectString}');
      var cClass = '';
  if("{!topParentId}".indexOf('{!$CurrentPage.parameters.id}') != -1)
   cClass = 'selectedRecord';
  var ul = '<ul><li id="{!topParentId}"  ><span class="' + cClass + '"  onclick="toggleChilds(\'' + '{!topParentId}' + '\',event)" ><b id="i{!topParentId}" class="minus" style="font-size: 1.5em;" >-</b>&nbsp;' +  accountValueMap['{!topParentId}'].{!RepersenterField} + '</span></li></ul>'  ;
  $(ul).appendTo("#parentDiv");
  appendUl('{!topParentId}','{!topParentId}');
      function appendUl(key)
      {
       $.each( accountMap[key], function( index, value ) 
       {
      var dclass = '';
      if(value.indexOf('{!$CurrentPage.parameters.id}') != -1)
       dclass = 'selectedRecord';
      var ul = '<ul class="' + key + '"><li id="' + value + '" ><span class="' + dclass + '" onclick="toggleChilds(\'' + value + '\',event)" ><b id="i' + value + '" class="minus" style="font-size: 1.5em;" >-</b>&nbsp;' + accountValueMap[value].{!RepersenterField} + "</span></li></ul>"  ;
      $(ul).appendTo("#" + key);
      if(value)
       appendUl(value);
   });
      }
      function toggleChilds(key,event)
      {
       $('.'+key).toggle('slow');
       $('#i'+key).toggleClass('minus');
       $('#i'+key).toggleClass('plus');
       if($('#i'+key).hasClass("minus")) 
        $('#i'+key).html("-");
         if($('#i'+key).hasClass("plus")) 
             $('#i'+key).html("+");
       event.stopPropagation();
      }
    </script>
</apex:component>

Step 3 : Now create a visualforce page, as shown below.

<apex:page standardcontroller="Account" showHeader="true" sidebar="true">
 <apex:pageblock title="Hierarchy">
  <c:DynamicHierarchyForBlog objectName="Account" FieldName="ParentId" RepersenterField="Name"/>
 </apex:pageblock>
</apex:page>
Open the page in the browser and pass a valid account id and the output will be a collapsible hierarchy as shown below.



This can plot the hierarchy of nth level and of any object. Post as comment if you have any questions.

Happy Coding!!

Apr 18, 2016

Getting Started With Communities

Communities is becoming a necessity to manage customers and partners and why not, it's easy that way isn't it? We (at Briskminds) are currently handling around 10 active projects where we need to implement the communities, but of-course we were also new to it few months back.

We've followed some simple steps to enable and use it, and would like to share that with my fellow community members as well. Let's explore more how we can enable and customize our community.


How to enable communities

  1. Go to Setup > App Setup > Customize > Communities > Settings
  2. Enable the checkbox "Enable communities"

Register For Domain

Once enabled the communities it will ask for the domain name, show in picture. Once registered for the domain you can now create your community, by clicking on “New Community” (Customize | Communities | Manage Communities, then click New Community) button.


Allowing profile to login in community

  1. Once you create new community then click on edit.
  2. It will show the screen as displayed in picture (please remember this, as we will refer the same Edit again and again)

  1. Click on “Members” tab
  2. Once clicked on “Members” tab, it will show the screen as displayed in picture

  1. Here you can enable profiles and give permissions to users
  2. If you are creating a community user then make sure profile assigned to that user is listed here (in “Selected Profile”) else user will not be able to do anything with the email which will be received after new user creation.

Allowing Tabs and Pages
  1. Click on “Edit” against your community
  2. Now click on “Tabs and Pages”, it will show the screen displayed in picture

  1. Select “Use Salesforce.com tabs” (let’s not dive into using site.com as it is a separate topic)
  2. Then you can select the tabs which you want to show to the community users
  3. Note – First tab selected will be the landing tab

Custom Branding
  1. Click on “Edit” against your community
  2. Now click on “Branding”, it will show the screen displayed in picture
  1. From here you can customize your headers and footers (formats are mentioned in picture) (which will be displayed on the native screens, and depends if you’ve applied on custom pages/tabs) and color theme to the community

Customize Login Page
  1. Click on “Edit” against your community
  2. Now click on “Login Page”, it will show the screen displayed in picture
  1. Now you can give your company logo in login page. Whenever user open your community link, then you can show your company logo in header and show your content in footer.
  2. If you need to completely change the login page to your visualforce page then we need to follow some more steps mentioned below :
(i) Create an apex class and visualforce page you want to show as your login page. Keep it simple for now.

Apex Class :
global with sharing class CustomLoginController 
{
  global String username {get; set;}
  global String password {get; set;}
  global CustomLoginController () {}
  
  global PageReference login() 
{
  return Site.login(username, password, null); 
  } 
}

Visualforce Page (please change this according to your need) :




Login to Community

Username
Password

(ii) Now go toSetup>Customize>Communities>Manage Comunities and click on force.com link as shown below

(iii) Now scroll down and click on edit "Site Visualforce Pages"

(iv) Now add the custom page you just created to "Enabled Visualforce Pages"

(v) Once saved, click on Edit as shown below :


(vi) Now add “CustomLogin” page as shown below. And save it.

(vii) Now click on "URL Redirect" as shown below :

(viii) Now add partial source URL (Ex. /support/login ) in Source URL textbox and partial target URL in (Ex. /support/CustomLogin) in Target URL textbox and click save.



Create New User
  1. Create a new account (Go to your org as internal user and then click on account tab and then new)
  2. Create a new contact record under newly created account (Go to the newly create account and then click on new on contact related list)
  3. Open contact record and click on “Manage External User” button (as shown in picture) and then click on “Enable Customer User” link, it will redirect you to user record
   4. When you click on Save button (on new user screen), please ensure that the current logged in user should have a role to create this new user otherwise it will give you error.


Publish It

Once you are done with everything and ready to use your community then you will click on publish as shown in picture

(From Setup, click Customize > Communities > Manage Communities. Click on edit button in the front of your community and then click on Publish button.)


Now you are all set to go. Get started with this hot topic, and please do share your thoughts or problem you may face.

Mar 19, 2016

Lightning Cheat Sheet - Level Basic

A very basic and overview which can solve your initial queries :

What is the Lightning Component Framework?

-> The Lightning Component framework is a UI framework for developing dynamic web apps for mobile and desktop devices.
-> It uses JavaScript on the client side and Apex on the server side.


Framework

-> The aura namespace contains components to simplify your app logic, and the ui namespace contains components for user interface elements like buttons and input fields


Visualforce and Lightning Comparison

-> Lightning components are client-side focused, making them more dynamic and mobile
friendly.
-> Visualforce components are page-centric and rely heavily on server calls.
-> Lightning components use Apex on the server side, organizations that can’t use Apex code can’t create Lightning components, but they can use Visualforce


Benefits 

-> You don't have to spend your time optimizing your apps for different devices as the components take care of that for you.
-> Uses a stateful client and stateless server architecture that relies on JavaScript on the client side to manage UI component metadata and application data.
-> The framework uses JSON to exchange data between the server and the client.


Lightning Component?

-> Components are the self-contained and reusable units of an app.
-> A component can contain other components, as well as HTML, CSS, JavaScript, or any other Web-enabled code.


Tools

-> You can use Developer Console to build lightning apps and components


Aura and Lightning?

-> Lightning components are based on the open source Aura framework available at https://github.com/forcedotcom/aura.
-> The Aura framework enables you to build apps completely independent of your data in Salesforce.

Many more to come to get you started with lightning, stay tuned.

Cheers!!

Feb 22, 2016

Trailhead - Navigate the Salesforce Advantage

I think most of you (probably all) are aware of TRAILHEAD!! An awesome tool design by a great team of Salesforce to help new and experience developers. It helped me a lot to get over lightning concepts and I hope you must have your own favorite list.






For everyone who is getting started with Salesforce or planning to get started have a very common question what is Salesforce? Why we should start working on Salesforce? These are the points which were (YES! were) missing from Trailhead. Again thanks to Trailhead which Salesforce recently launched which is all about this. 

Due to this one can easily get better understanding of Salesforce and will sort out many puzzles which may be running from a long time in mind. As we are all aware that how easy is to use trailhead, so these new modules just add "Cherry on the Cake". In these modules you will find information related to every aspect of Salesforce whether it is their Service, Security or their core values. Now it is easy for me to train newbies who joins my company as fresher. It tool a lot of initial headache and made my life easy. Am pretty sure it will not take much time even if anyone who doesn't know about Salesforce goes through it.

Best part is the security, which is a big concern now a days (even from long). Salesforce has a lot of security protocols which ensures safety of your data. I think if I remember correctly not even Salesforce internal members can see your data until you authorize them to do so. Would like to add one more point here, that there is a link to create free developer account and more details about different modules including the newly added IOT cloud.

Reference: https://developer.salesforce.com/trailhead/trail/salesforce_advantage



Happy Trailhead!

Jan 3, 2016

How to Whitelist All IPs in Salesforce

I saw this on many developer forums and stack exchange and many others are facing the same issue of how we can enable of all IPs in our organization. For developers this a big problem, as every-time you share the credentials with anyone you've to whitelist their IP so they can login without sending any security code to emails.

So here is sweet and short solution to it. You simply need to create a home page component (custom link) and use this code there :


var startingPoint = 0; 
var endpoint = 0; 

openPage(); 
function openPage() 
{ 
endpoint = startingPoint + 1; 
var win = window.open('https://ap2.salesforce.com/05G/e?IpStartAddress=' + startingPoint + '.0.0.0&IpEndAddress=' + endpoint + '.255.255.255&isdtp=vw',600,600); 
win.onload = function() 
{ 
win.document.getElementsByName('save')[0].click(); 
win.onunload = function() 
{ 
win.close(); 
startingPoint = startingPoint + 2; 
if(startingPoint <= 255) 
{ 
openPage(); 
} 
} 
} 
}


On home page layout you've to use this custom link. Make sure your browser is allowing the pop-ups as once you click on this link just sit back and relax as it will continuously calls the page and add IPs to your org.

Also in code I've "https://ap2.salesforce.com", please make sure you change it your base URL of the ORG (rest URL remain as is "/05G/e?IpStartAddress=' + startingPoint + '.0.0.0&IpEndAddress=' + endpoint + '.255.255.255&isdtp=vw',600,600")

Hope this helps. Cheers!!