Monday, April 6, 2015

Logic behind getRecord()

In Visualforce you can have 4 types of controllers:

Standard Controller class has a method called "getRecord()". It returns the record that is currently in context (e.g. Account, Contact, Opportunity, Custom_Object__c etc.), based on the value of the id query string parameter in the Visualforce page URL.

You can use this method in a controller extension class of a Visualforce page to get the record for a specific object. The most important point here is that you can get data in ONLY those which are referenced in a Visualforce markup. This method helps and allow you to not SOQL query to get data from associated fields of a specific object.

For example you have a Visualforce page to show Detail View of Opportunity but you need "Stage" field of Opportunity in associated Controller Extension class to perform some activities based on the value of "Stage" field.

The easy way is to query that particular record of Opportunity with the Id query string parameter in the Visualforce page URL.

The smartest way is to use getRecord() method and <apex:outputText> tag of Visualforce with an attribute of render=false. This will allow you to get the Stage field data without query into the Opportunity object.


Now first, create an Apex class. To create an Apex class Go to, Setup > Build > Customize > Develop > Apex Classes > New

Now copy and paste below code into the Apex class editor and Save it.

Visualforce Controller Extension Code

              --------------------------------------------------------------------------------------------
public with sharing class OpportunityCtrlExt{

    public Opportunity opportunityRecord {get; private set;}

    public OpportunityCtrlExt(ApexPages.StandardController stdController) {
        this.opportunityRecord = (Opportunity)stdController.getRecord();
        doProcessing();
    }
    
    private void doProcessing(){
        // IF Stage = Prospecting THEN 
        // disable Prospecting button and enable Closed Won and Closed Lost buttons
        if(opportunityRecord.StageName == 'Prospecting'){
             // Your logic here
        }
        // IF Stage = Closed Won or Closed Lost THEN 
        // enable Prospecting button and disable Closed Won and Closed Lost buttons
        else{
             // Your logic here
        }
   }

}
              --------------------------------------------------------------------------------------------


To create a Visualforce page Go to, Setup > Build > Develop > Pages

Now copy and paste below code into the Visualforce page editor and name this Visualforce page as "OpportunityCustomButtonsPage" and Save it.

Visualforce Page Code

--------------------------------------------------------------------------------------------
<apex:page standardController="Opportunity" extensions="OpportunityCtrlExt">

    <!-- This will render a standard detail page of Opportunty with all related lists -->
    <apex:detail subject="{!Opportunity.Id}" relatedList="true" title="true" showChatter="true" inlineEdit="true"  />

    <!--
        This is because we do not need to query Stage field in associated Controller Extension class
        because we are using getRecord() method of Standard Controller. If you will not use below line
        then you will need to query Stage field otherwise you will get an error saying:
        SObject row was retrieved via SOQL without querying the requested field: Opportunity.StageName 
    -->
    <apex:outputText value="{!Opportunity.StageName}" rendered="false"></apex:outputText>

</apex:page>
                   --------------------------------------------------------------------------------------------

Enable / Disable Buttons on Standard Detail Page

In Salesforce.com we always have 2 ways to implement a requirement or use case. One is Declarative "or" Point-And-Click tools and if any thing which we can not implement then we consider to go with another way which is Programmatic using Apex, Visualforce, SOQL, SOSL or Salesforce API's.

Here I am going to take one of the use case which I came across during implementation. A customer wanted to show custom buttons on Opportunity detail page and based on each button click they wanted to perform some actions on an Opportunity record (e.g. Update Stage field etc.). This can be achieved easily using Declarative "or" Point-And-Click tools. However they also wanted to Enable or Disable those Custom Buttons based on the value of Stage field in Opportunity record. This is something you cannot achieve via standard OOTB (out-of-the-box) features of Salesforce.com. So, now what to do?

Now lets take a specific example here. For example you have 3 custom buttons with following Name:

  • Prospecting
  • Closed Won
  • Closed Lost
To create a custom button Go to, Setup > Build > Customize > Opportunities > Buttons, Links, and Actions

After creating custom buttons, add them in Page Layouts of Opportunity.

To enable / disable those buttons on standard detail page of Opportunity, we need to override the standard detail page with a Visualforce page.

A Visualforce page must be using "Opportunity"  as a standard controller and an Apex class "OpportunityCustomButtonsCtrlExt" as a visualforce controller extension.

First, create an Apex class. To create an Apex class Go to, Setup > Build > Customize > Develop > Apex Classes > New

Now copy and paste below code into the Apex class editor and Save it.

Visualforce Controller Extension Code

              --------------------------------------------------------------------------------------------
public with sharing class OpportunityCustomButtonsCtrlExt{

    private boolean buttonProspecting;
    private boolean buttonClosedWon;
    private boolean buttonClosedLost;
    
    public Opportunity opportunityRecord {get; private set;}
    
    public boolean getButtonProspecting(){
        return buttonProspecting;
    }
    public boolean getButtonClosedWon(){
        return buttonClosedWon;
    }
    public boolean getButtonClosedLost(){
        return buttonClosedLost;
    }

    public OpportunityCustomButtonsCtrlExt(ApexPages.StandardController stdController) {
        this.opportunityRecord = (Opportunity)stdController.getRecord();
        enableDisableCustomButtons();
    }
    
    private void enableDisableCustomButtons(){
        // IF Stage = Prospecting THEN 
        // disable Prospecting button and enable Closed Won and Closed Lost buttons
        if(opportunityRecord.StageName == 'Prospecting'){
            buttonProspecting = true;
            buttonClosedWon = false;
            buttonClosedLost = false;
        }
        // IF Stage = Closed Won or Closed Lost THEN 
        // enable Prospecting button and disable Closed Won and Closed Lost buttons
        else{
            buttonProspecting = false;
            buttonClosedWon = true;
            buttonClosedLost = true;
        }
   }

}
              --------------------------------------------------------------------------------------------


To create a Visualforce page Go to, Setup > Build > Develop > Pages

Now copy and paste below code into the Visualforce page editor and name this Visualforce page as "OpportunityCustomButtonsPage" and Save it.

Visualforce Page Code

--------------------------------------------------------------------------------------------
<apex:page standardController="Opportunity" extensions="OpportunityCustomButtonsCtrlExt">

    <!-- This will render a standard detail page of Opportunty with all related lists -->
    <apex:detail subject="{!Opportunity.Id}" relatedList="true" title="true" showChatter="true" inlineEdit="true" oncomplete="javascript:location.reload();"  />

    <!--
        This is because we do not need to query Stage field in associated Controller Extension class
        because we are using getRecord() method of Standard Controller. If you will not use below line
        then you will need to query Stage field otherwise you will get an error saying:
        SObject row was retrieved via SOQL without querying the requested field: Opportunity.StageName 
    -->
    <apex:outputText value="{!Opportunity.StageName}" rendered="false"></apex:outputText>
    
    <script type="text/javascript">
    
    function checkButtonName(){
        if('{!buttonProspecting}' == true || '{!buttonProspecting}' == 'true') {
            // prospecting is an API Name of the custom button Prospecting
            // make sure you all letters must be small
            enableDisableButtons("prospecting");
        }
        if('{!buttonClosedWon}' == true || '{!buttonClosedWon}' == 'true'){
            // prospecting is an API Name of the custom button Closed Won
            // make sure you all letters must be small
            enableDisableButtons("closed_won");
        }
        if('{!buttonClosedLost}' == true || '{!buttonClosedLost}' == 'true'){
            // prospecting is an API Name of the custom button Closed Lost
            // make sure you all letters must be small
            enableDisableButtons("closed_lost");
        }
    }
    
    checkButtonName();
    function enableDisableButtons(btnName1) {
      try{
        var buttons = document.getElementsByName(btnName1);
        for (var i=0; i < buttons.length; i++) {
          buttons[i].className="btnDisabled ";
          buttons[i].disabled=true;      
        }
      } catch(e) {
      }
    }
    
    </script>

</apex:page>
                   --------------------------------------------------------------------------------------------


Now the last and final step is to override / replace detail page of Opportunity with a Visualforce page "OpportunityCustomButtonsPage" which you just created.

To override Detail View of Opportunity Go to, Setup > Build > Customize > Opportunities > Buttons, Links, and Actions > click "Edit" associated to View > select a Visualforce page "OpportunityCustomButtonsPage" from the drop-down menu  > click Save


Now Opportunity page should look like this:

IF Stage = Prospecting




IF Stage = Closed Won "or" Closed Lost






Convert Lead using Custom Button

To create a custom button for Lead Go Setup > Build > Customize > Lead > Buttons, Links, and Actions

Custom Button Code

{!REQUIRESCRIPT("/soap/ajax/33.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/33.0/apex.js")}

var r = confirm("Converting this Lead will create Account, Contact and Opportunity? Are you sure you would like to do this?");

if (r == true) {

   var leadToUpdate = new sforce.SObject("Lead");
   leadToUpdate.Id = "{!Lead.Id}";

   var result = sforce.connection.update([leadToUpdate]);
   
   var l = "{!Lead.Id}";
   var q = sforce.connection.query(
   "Select Id, MasterLabel from LeadStatus where IsConverted=true limit 1");
   
   records = q.getArray("records");
   var record = records[0].MasterLabel;

   var convert = new sforce.LeadConvert();
   convert.leadId = l;
   convert.convertedStatus = record;
   
   result = sforce.connection.convertLead([convert]);

   if (result[0].getBoolean("success")) {
      var o = result[0].accountId;
      window.location.href="/"+o;
   } 
   else {
      alert("Sorry Unable to convert Lead that is in use by workflow.")
   }

}

Sunday, April 5, 2015

Custom Buttons & Links in Service Cloud Console

Salesforce Service Cloud is doing a very important role for custom services. Whenever we need to implement Service Cloud we play with Service Cloud Console that helps custom service agent to make most out of it and increase productivity while they do work on a day to day basis.

Standard Salesforce features of Service Cloud Console are very powerful, robust and intuitive to customise. But when it comes to playing with Mashups (specifically Custom Buttons & Links) within Service Cloud Console is difficult.

Yes Salesforce has Salesforce Console Integration Toolkit (The Salesforce Console Integration Toolkit is a browser-based JavaScript API. It uses browsers as clients to display pages as tabs in the console.) to provides Developers with programmatic access to the Salesforce console so that you can extend it to meet your business needs. With the Salesforce Console Integration Toolkit, you can open and close tabs in the console to streamline a business process.
However, in the case of Custom Buttons & Links on standard detail pages, the Integration Toolkit is not available. This means we have to find some other way to open tabs (e.g. sub-tab, primary-tab).

Here we consider an example as a use case to open a sub-tab using a custom button on standard detail page of Case within Service Cloud Console.

To start, let’s create the button. Go to Setup-> Build > Customize -> Cases -> Buttons, Links, and Actions

Custom Button Code

//Copy and Paste the below code 

{!requireScript("/soap/ajax/33.0/connection.js")}
{!requireScript("/soap/ajax/33.0/apex.js")}

var caseId = "{!Case.Id}";

// It will execute if the Button/Link will be clicked from with in Service Cloud Console
if (typeof(srcUp) == 'function') {
   srcUp('/apex/CaseTransactionPage?isdtp=vw&id='+caseId);
}
// It will execute if the Button/Link will be clicked from normal Salesforce UI
else{
   window.open('/apex/CaseTransactionPage?isdtp=vw&id='+caseId);
}


Visualforce Code

<apex:page standardController="Case" tabStyle="Case">

    <apex:includeScript value="/support/console/33.0/integration.js"/>

    <script type="text/javascript">
        //Sets the title of the current tab to "Case Transactions Detail"
        window.onload = function setTitleConsole(){
            setTitle();
        }
        //Sets the title of the current tab to "Case Transactions Detail"
        function setTitle() {
            sforce.console.setTabTitle('Case Transaction Details');
        } 
    </script>
    
    <!-- Your Visualforce markup will be here -->
    

</apex:page>


Useful Resources

Get the Object Type by using sObject Describe call in Apex

public AccountControllerExtension(ApexPages.StandardController stdController){

// Get the record of sObject (e.g. Account, Contact etc.) by using the method "getRecord()" of StandardController
    sObject sObjectRecord = stdController.getRecord();

// Get the object type specifically by using Apex sObject Describe call
// In this case it will be Account
    String objectType = sObjectRecord.getSObjectType().getDescribe().getName();  

// Verify the Object Type
System.Debug('>>Object Type<<'+objectType);

}

Get the Picklist Values by using sObject Describe call in Apex

// Contains all Account.Industry values
Set<String> IndustryValues = new Set<String>();

// Get Account.Industry values from the field on Account object
Schema.DescribeFieldResult accountIndustry = Account.Industry.getDescribe();

List<Schema.PicklistEntry> accountIndustryValues = accountIndustry.getPicklistValues();        
for(Schema.PicklistEntry industryValue: accountIndustryValues){
IndustryValues.add(industryValue.getValue());
}

System.Debug('>>Account Industry Values<<'+IndustryValues);

Result should be as follows

>>Account Industry Values<<{Agriculture, Apparel, Banking, Biotechnology, Chemicals, Communications, Construction, Consulting, Education, Electronics, ...}

Convert Complex String into Normal Format in Apex

// An array contains lst of Strings 
// Name, Title/Role, Company Name 
List<String> lstIntroductionWords = new List<String>{'Marc Benioff', 'CEO', 'Salesfore.com'};

// A string contains senetence template for the introduction
String templateIntroduction = 'My name is {0}. I am The {1} of {2}.';    

// A string contains sentence with complete words populated in a template sentence
String completeIntroduction = String.format(templateIntroduction, lstIntroductionWords);    

// See the complete sentence for the introduction
System.Debug('>>Introduction<<'+completeIntroduction);

Result should be as below sentence
>>Introduction<< My name is Marc Benioff. I am The CEO of Salesfore.com.

Convert String into Acceptable DateTime in Apex

// API Response DateTime = 2015-03-16T16:04:56.0000000+00:00
// Acceptable Format = 2015-03-16 16:04:56

// DateTime in String format
String dateTimeInString = '2015-03-16T16:04:56.0000000+00:00';

// Convert String into DateTime using "replace" method of String and "Valueof" method of DateTime
DateTime acceptableDateTime = DateTime.Valueof(dateTimeInString.replace('T', ' ')); 

System.Debug('>>Acceptable DateTime :<<'+acceptableDateTime);

Result

>>Acceptable DateTime :<< 2015-03-16 16:04:56

Why didn't the Force.com Platform Developers use SQL?

SOQL (Salesforce.com Object Query Language)

As a developer, you are no doubt already familiar with some query languages. The most common query language is SQL, or Standard Query Language, the universal standard for interacting with relational databases.

Just as the Force Platform data repository is similar to a relational database, SOQL is similar to SQL. In most places where there is overlapping functionality, the syntax for SOQL is identical to SQL. But there are a few important differences between the two data access languages.
  • SOQL is a query-only language – SQL has syntax for both reading and writing data, while SOQL is only used to retrieve records from your Force Platform objects. Later in this chapter, you will learn about how to write data using Apex data manipulation language.
  • SOQL uses relationships, not joins – In SQL, you implement relationships between tables using join syntax in the where clause of the query. SOQL syntax recognises relationship fields to identify the connections between objects, but does not support join syntax. You will see how to use relationships in your SOQL statements in the next section.
  • SOQL does not support all SQL keywords – SOQL syntax is described in brief in the following section, and in more detail in the Force Platform API documentation. You should assume that SQL syntax not covered in the documentation is not accepted in SOQL.

Why not SQL?

As a developer, your career might have encompassed using several different relational databases, and all of them used a similar form of SQL. You might be asking yourself the question in the title of this sidebar—why didn't the Force Platform developers use SQL?

The simple answer is that Force Platform objects are not the same as SQL tables and the Force Platform data store is not the same as a relational database. Access to data is always through some dialect, rather than directly, whether that interface is SQL or something else. In this fashion, SOQL provides query capabilities for Force Platform objects. The Force Platform environment offers you a lot of functionality and developer productivity based on the use of these objects, which are not the same as relational tables.

The complete Force Platform platform gives you everything you need to store and manipulate your data–the language and methods used to accomplish these ends are just a little different than those used for classic relational databases.

Journey from SQL to SOQL

Pagination with a Standard List Controller


In Visualforce you can add pagination logic in a visualforce page using a Standard List Controller by helping standard functions of pagination "first", "previous", "next", "last". This page also have a capability to mass update records using Inline Editing Support.


If you create a visualforce page with the following markup:

<apex:page standardController="Account" recordSetVar="accounts" tabstyle="Account">

    <apex:form >

        <apex:pageblock id="customerPageBlock" title="Mass Update Customers">

            <apex:pageblocktable value="{!accounts}" var="acct" id="customerTable">

                <apex:column headerValue="Customer ID">
                    <apex:outputField value="{!acct.Id}"/>
                </apex:column> 
                <apex:column headerValue="Customer Name">
                    <apex:outputField value="{!acct.Name}"/>
                </apex:column> 
                <apex:column headerValue="Industry">
                    <apex:outputField value="{!acct.Industry}"/>
                </apex:column>                             
                <apex:inlineEditSupport event="onClick"/>
            </apex:pageblocktable>

            <center>
                <apex:panelGrid columns="7">
                    <apex:commandButton action="{!quickSave}" value="Save"/>
                    <apex:commandButton action="{!Cancel}" value="Cancel"/>
                    <apex:inputHidden />              
                    <apex:commandButton disabled="{!NOT(hasPrevious)}" action="{!first}" value="First"/>
                    <apex:commandButton disabled="{!NOT(hasPrevious)}" action="{!previous}" value="Previous"/>
                    <apex:commandButton disabled="{!NOT(hasNext)}" action="{!next}" value="Next"/>
                    <apex:commandButton disabled="{!NOT(hasNext)}" action="{!last}" value="Last"/>
                </apex:panelGrid>
            </center>

        </apex:pageblock>
    </apex:form>
</apex:page>








Considerations

  • By default, a standard list controller returns 20 records on the page.
  • To control the number of records displayed on each page, use a controller extension to set the pageSize. See Controller Extensions.

Saturday, April 4, 2015

Visualforce Tips & Tricks

outputLink in Visualforce

<apex:page >
    <apex:pageBlock title="Visualforce Pages">
        <apex:outputLink value="{!$Page.SearchPage}?id=101" target="_blank">Search Page</apex:outputLink>    
    </apex:pageBlock>
</apex:page>


MVC & Visualforce

What is MVC?

Model–View–Controller (MVC) is a software architectural pattern for implementing user interfaces. It divides a given software application into three interconnected parts:

  • Model - A model consists of application data, business rules, logic and functions
  • View - A view can be any output representation of information
  • Controller - A controller accepts input and converts it to commands for the model or view

MVC Paradigm






Visualforce and the MVC Pattern






MVC Example in Visualforce






Declarative v/s Programmatic Tools in Salesforce

In Salesforce.com we have 2 ways to customise our Salesforce.com organisation:

  • Declarative (Point-And-Click)
  • Programmatic (Apex / Visualforce / API)



Advantages of Declarative v/s Programmatic




Most complete and robust solutions actually use a combination of declarative and programmatic solutions.

Developers should understand how to develop using both declarative and programmatic features of Salesforce.com.

Always try to customise Salesforce.com using OOTB (out-of-the-box) "or" declarative "or" Point-And-Click features of Salesforce.com.