Wednesday, February 27, 2013

Best Practices For Salesforce Coding

  • Use header comments on top classes as below:

      /**
        @ name                      :
        @ author                    :
        @ date                      :
        @ description               :
        @ VF page Name              :
      */

  • Variable/method names needs to be in camelCase as possible. Like creatCase(), getClosedWonOpportunity() etc.

  • Variables names must be meaningful as possible, don't like x, y etc


  • Use curly braces with same line instead of next line in if/else and loops constructs as below:
       if(bla bla){

       }

  • Comments at on every possible complex logic, on top of each methods also about its working.


  • Keep method as possible small , if going logic more than 50 rows, then break that into other method.


  • Test classes must be meaningful, means must have asserts of the main logic, must have coverage near to 80% as possible (at-least 75% is required), use separate test class to cover each separate apex class.


  • Use proper Oops concept as possible , means use private where ever possible, extends, method overriding , method overloading etc.


  • Don’t hard code ids and any hard code values in code, use query to fetch data or in test classes make new objects.


  • Don’t hard code message or error text, try to use Label as possible (If client says).


  • Use components as possible for header, footer in pages.


  • use standard apex tags as possible.


  • Whenever possible make your Utility class which has useful, re-used methods and put your methods in that and use that class in every class logic.


  • If any trigger logic is very big, then try to make one class and put your logic in that class and call that class in your trigger. Keep trigger small and as simple as possible.

  • Check if condition before using the list. eg: 
     if(ContactList.size() > 0)
     {bla bla}

  • Avoid Nested loops, which may cause maximum script statements governor limits to be hit. Should make use of Maps to avoid nested loops.


NOTE: The aforementioned Best Practices are according to me. Salesforce itself output their own Best Practices. I have cited and summarized some of the excerpts it.

Wednesday, February 20, 2013

Google Map On Detail Page Without Controller


Lot of time we need to implement Google map direct on production. On production we can't create classes or contorllers. But we can create VF pages. So I tried to solve this problem. 
I implemented Google Map on Visualforce page, you can Implement this as inline VF page of any object. 
I am using here Account object and Billing Adress for pointing -

For this you need two jquery file that will stored in Static Resource, 
download from this link - 

and then Copy and paste this code on visualforce page. - 


<apex:page standardController="Account" showHeader="false" sidebar="false" >  
   <apex:includeScript value="https://maps.googleapis.com/maps/api/js?sensor=false"/>  
   <apex:includeScript value="{!URLFOR($Resource.jQuery, 'js/jquery-1.6.2.min.js')}"/>  
   <apex:includeScript value="{!URLFOR($Resource.jQuery, 'js/jquery-ui-1.8.16.custom.min.js')}"/>  
   <apex:includeScript value="{!URLFOR($Resource.jqPlugin, '/jquery.blockUI.js')}"/>  
   <apex:stylesheet value="{!URLFOR($Resource.jQuery, 'css/ui-lightness/jquery-ui-1.8.16.custom.css')}"/>  
   <script>  
      var console = {log: function(){}};
      var map,geocoder,infowindow;  
      var latLngs = [];  
      $j = jQuery.noConflict();   
      $j(document).ready(function(){  
        initialize();  
      });  
      function initialize() {  
       geocoder = new google.maps.Geocoder();  
       //initial cordinates for map init  
         
       var latlng = new google.maps.LatLng(37.09024, -95.712891);  
       //var latlng = new google.maps.LatLng(0, 0);  
       var myOptions = {  
         zoom: 10,  
         center: latlng,  
         mapTypeId: google.maps.MapTypeId.ROADMAP  
       };  
       map = new google.maps.Map($j('#map')[0], myOptions);  
       codeAddress();  
      }  
     function codeAddress(){  
       var address = '{!Account.BillingStreet},{!Account.BillingCity},{!Account.BillingState},{!Account.BillingCountry}';  
        console.log(address);  
       geocoder.geocode( { 'address': address }, function(results, status) {  
          //if it is a success  
          
          if (status == google.maps.GeocoderStatus.OK) {  
            var location = results[0].geometry.location;  
           
            var marker=addMarker(location );  
            //attach info window to the marker  
            attachInfoWindow(marker,results[0]);  
          }  
          else {  
            //alert(status);  
          }  
        });   
      }  
     
      function addMarker(location) {  
       marker = new google.maps.Marker({  
           position: location,  
           map: map  
         });  
       var latlngbounds = new google.maps.LatLngBounds();  
       latlngbounds.extend(marker.getPosition());  
       map.fitBounds(latlngbounds);  
       map.setZoom(14);  
       return marker;  
      }  
     //this function shows the address of a marker when it is clicked  
     function attachInfoWindow(marker,address){  
        google.maps.event.addListener(marker, 'click', function() {  
          if(infowindow!=null)  
           {  
             infowindow.close();  
           }  
        
         var contentString = '<div class=" ui-state-active ui-corner-top" style="font-size: 1em; padding: 5px;">Address</div>'  
                   +'<div class="ui-widget-content ui-corner-bottom" style="font-size: .9em; padding: 15px;">'+address.formatted_address+'</div>';  
         infowindow = new google.maps.InfoWindow({  
           content: contentString  
         });  
          infowindow.open(map,marker);  
        });  
     }  
   </script>  
   <style>  
     #map {  
       width:100%;  
       height:200px;   
       margin-left:0;  
     }  
   </style>  
     <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8" />
   <div id="map" class="ui-widget-content ui-corner-all ui-state-default"></div>  
 </apex:page>
                       

Wednesday, February 13, 2013

Transient Keyword

Many times we are struggling with view state error on visualforce page at the time of uploading files.
Salesforce provides facility to a upload file upto 10mb, But when we try to upload file through visualforce page then visualforce page limit (135kb) create a wall. It is I try to jump this wall and upload the files through visual force page.

Using Transient Keyword  we can achieve this. Decalaring Variables as transient to reduces view states. View state maintains state of the Database between request and Visualforce page.

I try to explain this using code -

Controller
public class UploadFileDemo


    public Attachment attch{get;set;} 
    public Transient blob myAttachedBody {get; set;}
    
    public UploadFileDemo()
    {
          attch = new Attachment();
    }
    public void uploadFile()
    {
          attch.body = myAttachedBody;
          attch.parentId = parentIdOfRelatedObject;
          insert attch;
    }
}
VisualForce page
<Apex:page>
  <apex:form>
      <Apex:pageblock> 
          <apex:inputFile id="idSelectFile" fileName="{!attch.Name}"  value="{!myAttachedBody}" contentType="{!attch.contentType}"  ></apex:inputFile>
            <apex:commandbutton value="Upload" action="{!uploadFile}"/>
      </apex:pageblock>
  </apex:form>
</apex:page>