Saturday, February 4, 2012

Account address to be displayed as single block

Small code snippet to display Account address as a single block just like in standard page

<apex:outputText label="Shipping Address"
                    escape="false"
                    value="{!IF(NOT(ISNULL(Account.ShippingStreet)),'{0}<br/>{1}, {2} {3}<br/>{4}', '&nbsp;')}">
                   
                    <apex:param value="{!Account.ShippingStreet}" />
                    <apex:param value="{!Account.ShippingCity}" />
                    <apex:param value="{!Account.ShippingState}" />
                    <apex:param value="{!Account.ShippingPostalCode}" />
                    <apex:param value="{!Account.ShippingCountry}" />
                </apex:outputText>

Wednesday, January 25, 2012

Identifying SobjectType Dyanamically

getKeyPrefix of Schema.getGlobalDescribe can be used to identify dynamically the SobjectType in Apex.

String prefix = recordId.substring(0,3);
String objectType;
Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
for(Schema.SObjectType s : gd.values()){
    if(prefix == s.getDescribe().getKeyPrefix()){
        objectType = s.getDescribe().Name;
    }
}

recordId consists the Id of the sobject Record for whose SobjectType needs to be identified. Above piece of code does it well.

Wednesday, January 11, 2012

Build your Own Standard set controller

Standard set controller can be used for many objects . Recently i found that it cannot be used with activity objects(Open activity and activity history). Also there are many other Restrictions placed on these objects. You cannot query on these objects directly. It has to be a nested SOQL within an object using a relationship name.

So coming back to my requirement i needed to roll up related list for all the activities in the account hierarchy for the topmost parent. For other related list i achieved it through standardset controller. But for activity alone i created a class which would behave like a standard set controller.

public class SetActivityClass {
        public integer pagenumber{get;set;}
        public integer totalpages{get;set;}
        public integer pagesize{get;set;}
        public list<sobject> sobjectList{get;set;}       
 public SetActivityClass(list<sobject> sobjectList){
        pagenumber =1;
        pagesize = 60;
        this.sobjectList=sobjectList;
        totalpages= Integer.valueof(math.ceil((double)sobjectList.size()/(double)pagesize ));
        }
        public boolean gethasprevious(){
          return (pagenumber != 1);
        }
        public boolean gethasnext(){
            return (pagenumber != totalpages);
        }
        public pagereference Previous(){
        if(gethasprevious())
            pagenumber--;
            return null;
        }
        public pagereference next(){
        if(gethasnext())
            pagenumber++;
            return null;
        }
        public list<sobject> getRecords(){
        list<sobject> Sactivity = new list<sobject>();       
            for(integer counter2=(pagenumber-1)*pagesize;counter2<(math.min(pagenumber*pagesize,sobjectList.size()));counter2++){
                Sactivity.add(sobjectList.get(counter2));
            }
            return Sactivity;
        }
          
    } 

oActivityHistory= new SetActivityClass(ActivityHistoryList);
        oOpenActivity= new SetActivityClass(OpenActivityList); 


public List<OpenActivity> getGoToListOpenActivities() {
    return oOpenActivity.getRecords();       
    }

public List<ActivityHistory> getGoToListActivityHistories() {
    return oActivityHistory.getRecords();       
    }

Just like the standard set controller, this SetActivityClass has methods to return next set or previous set of records. These can be added to command links as they are pagereference method. Also Hasprevious and Hasnext can be called from the page to check if the previous or next set of records exist.Pagenumber denotes the current page number. Pagesize determines no of records to be displayed in the page. I would recommend a size of 40 -60 in a page for better readability by Users(I have hardcoded it as 60). Total pages is calculated based on this pagesize.

Also note that getRecord function accepts and returns generic sobject. I used the same class for both activityhistory and openactivity.This Class can be slightly tweaked to handle list of objects of your custom class  as well.

Here is how i would display it in the page

<apex:panelGrid columns="2">                 
 <apex:commandLink action="{!oOpenActivity.previous}" rendered={!oOpenActivity.hasPrevious}"> Previous </apex:commandLink>
  <apex:commandLink action="{!oOpenActivity.next}" rendered="{!oOpenActivity.hasNext}" >Next </apex:commandLink>           
  </apex:panelGrid>

<apex:pageBlockTable id="tableMasterAccountOpenActivities" var="openact"  value="{!GoToListOpenActivities}">
 <apex:column .....
.......
</apex:pageblocktable>

And whenever the next and previous is click make sure atleast the pageblock tabele is rerendered if not the whole page based on your logic. I  have shown the VF for openactivity. similarly u can use it for activity history. Also you can use the same logic in building your own custom class wrapper object standard set controller this way.

Saturday, January 7, 2012

Javascript for Ghost Text in Salesforce

There will be a need to add ghost text which will be like a help text or format in which the value needs to be there for a particular input field in visual force. I would suggest use visual force help text for it. But if ghost text is required use the following script.



Trick here use the script after all the component is loaded preferably before </apex:page> tag.

        <script type="text/javascript">  
            var txtContent  = document.getElementById("{!$Component.theform.thepb.thepbs.mp}");
            var defaultText = '+91 - *** *** ****';
            txtContent.value = defaultText;           
            txtContent.style.color = '#CCC';           
            txtContent.onfocus = function() {
              if (this.value == defaultText) {   
                this.value = '';
                this.style.color = '#000';
              }
            }
            txtContent.onblur = function() { 
              if (this.value == '') {   
                this.value = defaultText;
                this.style.color = '#CCC';
              }
            }
        </script>  

Also Make sure to handle the save if the field is filled with ghost text(Default text here).

Friday, December 9, 2011

Cool links for salesforce.com tools and best practices

I was going through the Best practices for force.com and Trigger template. It will be really helpful if we could follow it in our code.

You can also find lots of interesting tools for salesforce.com here.

Found this awesome IDE and data loader on the cloud !!! - Workbench . I would have loved to have metadata export on this. If anyone knows a tool not an app through which we can export metadata (not like an XML) more like a spreadsheet which can be used for documentation and data mapping please drop a comment here.

Finally Vote for all the ideas in this link. These are all the features worth having in SFDC.

There are many a times where we need to mimic a standard page through VF. Creating them to mimic it is a hard thing. But it can be done with a single click , whole code gets generated. You can check that out here. Pretty cool stuff aint it.