Dec 27, 2012

Streaming APIs - Easy Code


Streaming API is useful when you want notifications to be pushed from the server to the client based on criteria that you define.

The sequence of events when using Streaming API is as follows: (explained in detail later)
1. Create a PushTopic based on a SOQL query. This defines the channel.
2. Clients subscribe to the channel.
3. A record is created or updated (an event occurs). The changes to that record are evaluated.
4. If the record changes match the criteria of the PushTopic query, a notification is generated by the server and received by the subscribed clients.

Before we get started, I recommend you to go through these topics:

1) Push Technology
2) Bayeux Protocol, CometD, and Long Polling


We will achieve this once we are done with all steps (given below):





Now follow these steps:

Prerequisites:
1) The “Streaming API” permission must be enabled -> "Your Name > Setup > Customize > User Interface"
2) The logged-in user must have “Read” permission on the PushTopic standard object to receive notifications.
3) The logged-in user must have “Create” permission on the PushTopic standard object to create and manage PushTopic records.
4) The logged-in user must have “Author Apex” permissions to create a PushTopic by using the Developer Console.


Step 1: Create an Object - In our case we will use Account

Step 2: Create a PushTopic
Use the Developer Console to create the PushTopic record. You can use either Developer Console or Workbench. If needed these records can be updated.

"Your Name > Developer Console"


PushTopic pushTopic = new PushTopic();
pushTopic.Name = 'RefreshAccounts';
pushTopic.Query = 'SELECT Id, Name FROM Account';
pushTopic.ApiVersion = 26.0;
pushTopic.NotifyForOperations = 'All';
pushTopic.NotifyForFields = 'Referenced';
insert pushTopic;


Step 3: Create Static resource

1. Download the CometD compressed archive (.tgz) file from http://download.cometd.org/cometd-2.2.0-distribution.tar.gz
2. Extract the following JavaScript files from cometd-2.2.0-distribution.tar.gz:
• cometd-2.2.0/cometd-javascript/common/target/org/cometd.js
• cometd-2.2.0/cometd-javascript/jquery/src/main/webapp/jquery/jquery-1.5.1.js
• cometd-2.2.0/cometd-javascript/jquery/src/main/webapp/jquery/json2.js
• cometd-2.2.0/cometd-javascript/jquery/src/main/webapp/jquery/jquery.cometd.js


File Name
Static Resource Name
cometd.js
Cometd
jquery-1.5.1.js
Jquery
json2.js
json2
jquery.cometd.js
jquery_cometd




Step 4: Test the PushTopic Channel

Here is the code sample

Visualforce Page


<apex:page id="PG" controller="StreamingAPIController">
<apex:form id="FRM">

    <apex:includeScript value="{!$Resource.cometd}"/>
    <apex:includeScript value="{!$Resource.jquery}"/>
    <apex:includeScript value="{!$Resource.json2}"/>
    <apex:includeScript value="{!$Resource.jquery_cometd}"/>

    <apex:actionFunction name="GetRefreshedAccounts" reRender="PB,PBT"/>

    <script type="text/javascript">
        (function($)
        {
            $(document).ready(function() {
                
                // Connect to the CometD endpoint
                $.cometd.init({
                    url: window.location.protocol+'//'+window.location.hostname+'/cometd/24.0/',
                    requestHeaders: { Authorization: 'OAuth {!$Api.Session_ID}'}
                });
                
                // Subscribe to a topic. JSON-encoded update will be returned in the callback
                // In this example we are using this only to track the generated event
                $.cometd.subscribe('/topic/RefreshAccounts', function(message)
                {
                    //You can use message as it will return you many attributes
                    //I am just using to track that event is generated
                    GetRefreshedAccounts();
                });

            });
        })(jQuery)
    </script>

    <apex:pageBlock id="PB">
        <apex:variable var="count" value="{!0}" />
        <apex:pageBlockTable id="PBT" value="{!getRefreshedAccount}" var="AllAcc">
            
            <apex:column headerValue="S.No.">
                <apex:variable var="count" value="{!count+1}" />
                {!count}
            </apex:column>
            <apex:column value="{!AllAcc.Name}" headerValue="Name"/>
            
        </apex:pageBlockTable>
    </apex:pageBlock>

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

Apex Class


public class StreamingAPIController
{
    //Everytime page is reRendered it will get refreshed values of account
    public List<Account> getRefreshedAccount
    {
        get
        {
            return [select Id, Name from Account LIMIT 50000] ;
        }
        set;
    }
    
    public StreamingAPIController()
    {
    }
}


This is very small and simple sample code, you can do a lot more with streaming APIs. Please refer these documents to learn more:

1) http://www.salesforce.com/us/developer/docs/api_streaming/api_streaming.pdf
2) http://www.salesforce.com/us/developer/docs/api_streaming/index.htm
3)http://wiki.developerforce.com/page/Getting_Started_with_the_Force.com_Streaming_API

Dec 22, 2012

Uploading Multiple Attachments into Salesforce - Simple Code

Okay, so here is the simple code to upload multiple attachments into Salesforce. Please note that I've used standard controller ("Account" in the code) so you need to pass the record Id in parameter. You can also change this according to your need as code is dynamic.

So first option allow you to select how many files you want to upload. Say, you have selected "5", then it will give you 5 options to select files and once you click on "Upload" it will upload the files as attachments to the associated record.



Visualforce Page Code:


<apex:page standardController="Account" extensions="MultipleUploadController">
    <apex:form>
        <apex:pageBlock title="Upload Multiple Attachment to Object">
            
            <apex:pageBlockButtons>
                <apex:commandButton value="Upload"  action="{!SaveAttachments}"/>
            </apex:pageBlockButtons>
            
            <apex:pageMessages id="MSG"/>
            <apex:actionFunction name="ChangeCount" action="{!ChangeCount}"/>
            
            <apex:pageblocksection>
                            
                <apex:pageBlockSectionItem>
                    <apex:outputLabel value="How many files you want to upload?"/>
                    <apex:selectList onchange="ChangeCount() ;" multiselect="false" size="1" value="{!FileCount}">
                        <apex:selectOption itemLabel="--None--" itemValue=""/>
                        <apex:selectOptions value="{!filesCountList}"/>
                    </apex:selectList>
                </apex:pageBlockSectionItem>
            
            </apex:pageblocksection>
            
            <apex:pageBlockSection title="Select Files" rendered="{!IF(FileCount != null && FileCount != '', true , false)}">
                <apex:repeat value="{!allFileList}" var="AFL">
                    <apex:inputfile value="{!AFL.body}" filename="{!AFL.Name}" />
                    <br/>
                </apex:repeat>
            </apex:pageBlockSection>
            
        </apex:pageBlock>
    </apex:form>
</apex:page>


Apex Code:


public class MultipleUploadController
{   
    //Picklist of tnteger values to hold file count
    public List<SelectOption> filesCountList {get; set;}
    //Selected count
    public String FileCount {get; set;}
    
    public List<Attachment> allFileList {get; set;}
    
    public MultipleUploadController(ApexPages.StandardController controller)
    {
        //Initialize  
        filesCountList = new List<SelectOption>() ;
        FileCount = '' ;
        allFileList = new List<Attachment>() ;
        
        //Adding values count list - you can change this according to your need
        for(Integer i = 1 ; i < 11 ; i++)
            filesCountList.add(new SelectOption(''+i , ''+i)) ;
    }
    
    public Pagereference SaveAttachments()
    {
        String accId = System.currentPagereference().getParameters().get('id');
        if(accId == null || accId == '')
            ApexPages.addmessage(new ApexPages.message(ApexPages.Severity.ERROR,'No record is associated. Please pass record Id in parameter.'));
        if(FileCount == null || FileCount == '')
            ApexPages.addmessage(new ApexPages.message(ApexPages.Severity.ERROR,'Please select how many files you want to upload.'));

        List<Attachment> listToInsert = new List<Attachment>() ;
        
        //Attachment a = new Attachment(parentId = accid, name=myfile.name, body = myfile.body);
        for(Attachment a: allFileList)
        {
            if(a.name != '' && a.name != '' && a.body != null)
                listToInsert.add(new Attachment(parentId = accId, name = a.name, body = a.body)) ;
        }
        
        //Inserting attachments
        if(listToInsert.size() > 0)
        {
            insert listToInsert ;
            ApexPages.addmessage(new ApexPages.message(ApexPages.Severity.INFO, listToInsert.size() + ' file(s) are uploaded successfully'));
            FileCount = '' ;
        }
        else
            ApexPages.addmessage(new ApexPages.message(ApexPages.Severity.ERROR,'Please select at-least one file'));
            
        return null;
    }
    
    public PageReference ChangeCount()
    {
        allFileList.clear() ;
        //Adding multiple attachments instance
        for(Integer i = 1 ; i <= Integer.valueOf(FileCount) ; i++)
            allFileList.add(new Attachment()) ;
        return null ;
    }
}


You can enhance the code if you like, as I've provided the basic code which is re-usable. Also you can change the object passed in standard controller and code will handle the rest. URL should have ID else you will get error on UI :-)

Say, I've saved my VFP code as "MultipleUpload", so my URL will be https://...../apex/MultipleUpload?id=XXXXXXXXXXXXXXX (account id in this code).

Happy Coding.

Dec 19, 2012

Reading Visualforce Page Code In Apex

Recently faced a strange requirement to change the Visualforce page code dynamically (apologies can't disclose the complete scenario)

So would like to share the small POC with code. Code will take Visualforce Page name as parameter and will return you the code written for that VFP as text. For example, this is my Visualforce Page saved with name "VisualforceCode"


<apex:page id="PG" controller="VisualforceCodeController">
<apex:form id="FRM">
    <apex:pageMessages id="PM"/>
    <apex:pageBlock id="PB">
        
        <apex:commandLink value="See Magic" action="{!DisplayCode}" >
            <apex:param assignTo="{!CurrentPageName}" value="{!$CurrentPage.Name}"/>
        </apex:commandLink>
        
        <br/> <br/>

        <apex:outputPanel id="OPT" rendered="{!showCodeSection}">
            <apex:outputLabel value="{!PageText}"/>
        </apex:outputPanel>
    
    </apex:pageBlock>
</apex:form>
</apex:page>


Now I want to read the code written in this page, so here is the working code which send page name as parameter in "UtilClass" to get the code as text:


public class VisualforceCodeController
{
    //To display section which hold code as text of VF page
    public boolean showCodeSection {get; set;}
    
    //To hold VF Code as text
    public String PageText {get; set;}
    
    //Hold current page name
    public String CurrentPageName {get; set;}
    
    public VisualforceCodeController()
    {
        CurrentPageName = '' ;
        showCodeSection = false ;
    }
    
    public PageReference DisplayCode()
    {
        if(CurrentPageName != '')
        {
            //Fetching VF code
            PageText = UtilClass.VFPageCode(CurrentPageName) ;
            showCodeSection = true ;
        }
        return null ;
    }
}


To get the visualforce page name I've used "{!$CurrentPage.Name}" which is a global variable

Here Util Class code:


//General Class with static methods
public class UtilClass
{
    //Method will take visualforce page name as parameter and returns the code written in it
    public static String VFPageCode(String PageName)
    {
        ApexPage testPage = new ApexPage();
        String PageText = '' ;
        
        if(PageName != '')
        {
            //Fetching visualforce page code
            testPage = [Select Id, Markup from ApexPage where name =: PageName];
            PageText = testPage.markup ;
        }
        return PageText ;
    }
}

There are many other methods you can use with "ApexPage" mentioned here. So if you want to update the VFP code from apex dynamically you can use "ApexPage"

Nov 23, 2012

Page Block Table With Dynamic Columns In Salesforce

This is something extensively used, but every time I need to look for some easy code.

So here is the solution (apologies as I've not covered the negative cases in code, and I hope you all are smart enough to take care of that). Requirement is to build the dynamic page block table with dynamic columns, but this is not it. It should be so dynamic that user can select the object and it's fields by himself and nothing should be hard-coded. So first of all I've provided a picklist with all objects (not all objects... why? Take a look at it Please Remove The System Objects From My sObject List)

Visualforce Page Code:

<apex:page controller="DynamicTableController">
<apex:pageBlock >
    <apex:form >
        <apex:actionFunction name="ObjectFileds" action="{!ObjectFields}"/>
        
        <apex:commandButton  value="Show Table" action="{!ShowTable}"/>
        
        <apex:pageBlockSection >
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="Select Object"/>
                <apex:selectList multiselect="false" size="1" value="{!SelectedObject}" onchange="ObjectFileds();">
                    <apex:selectOption itemLabel="--None--" itemValue="--None--"/>
                    <apex:selectoptions value="{!supportedObject}" />
                </apex:selectlist>
            </apex:pageBlockSectionItem>
            
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="Select Field"/>
                <apex:selectList multiselect="true" size="5" value="{!SelectedFields}">
                    <apex:selectOption itemLabel="--None--" itemValue="--None--"/>
                    <apex:selectoptions value="{!fieldLableAPI}" />
                </apex:selectlist>
            </apex:pageBlockSectionItem>
            
            <apex:pageBlockTable rendered="{!IF(ObjectList.size > 0 , true , false)}" value="{!ObjectList}" var="rec">
                <apex:column value="{!rec.Id}" rendered="{!IF(SelectedFields.size == 0 , true, false)}"/>
                <apex:repeat value="{!SelectedFields}" var="FieldLable">
                    <apex:column value="{!rec[FieldLable]}" rendered="{!IF(FieldLable != '--None--' , true, false)}"/>
                </apex:repeat>
            </apex:pageBlockTable>
            
            <apex:outputPanel rendered="{!IF(ObjectList.size < 1 , true , false)}">
                <apex:pageMessage severity="ERROR" summary="No records to display"/>
            </apex:outputPanel>
            
        </apex:pageBlockSection>
        
    </apex:form>
</apex:pageBlock>
</apex:page>


Apex Code (Class):

public class DynamicTableController
{
    //List displayed on UI
    public List<selectoption> supportedObject {get; set;}
    
    //Selected Object
    public String SelectedObject {get; set;}
    
    //Global describe
    Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
    Set<String> objectKeys = gd.keySet();
    
    //Field Select List
    public List<SelectOption> fieldLableAPI {get; set;}
    
    //Selected fields to be displayed in table
    public List<String> SelectedFields {get; set;}
    
    //List to maintain dynamic query result
    public List<sObject> ObjectList {get; set;}
    
    
    //Constructor
    public DynamicTableController()
    {
        //Initialize
        supportedObject = new List<selectoption>() ;
        SelectedObject = '' ;
        fieldLableAPI = new List<SelectOption>() ;
        SelectedFields = new List<String>() ;
        ObjectList = new List<sObject>() ;
        
        //Get only reference to objects
        for(Schema.SObjectType item : ProcessInstance.TargetObjectId.getDescribe().getReferenceTo())
        {
            //Excluding custom setting objects
            if(!item.getDescribe().CustomSetting)
            {
                //Adding to list
                supportedObject.add(new SelectOption(item.getDescribe().getLocalName().toLowerCase() , item.getDescribe().getLabel() ));
            }
        }
        
    }
    
    //Get fields of selected object
    public void ObjectFields()
    {
        if(SelectedObject != '--None--')
        {
            //Creating sObject for dynamic selected object
            Schema.SObjectType systemObjectType = gd.get(SelectedObject);
            //Fetching field results
            Schema.DescribeSObjectResult r = systemObjectType.getDescribe();
                
            Map<String, Schema.SObjectField> M = r.fields.getMap();
            //Creating picklist of fields
            for(Schema.SObjectField fieldAPI : M.values())
            {
                fieldLableAPI.add(new SelectOption(fieldAPI.getDescribe().getName() , fieldAPI.getDescribe().getLabel())) ;
            }
        }
    }
    
    public void ShowTable()
    {
        //Creating dynamic query with selected field
        String myQuery = 'Select Id ' ;
        
        for(String field : SelectedFields)
        {
            if(field.toLowerCase() != 'id' && field.toLowerCase() != '--none--')
            myQuery += ','+ field + ' ' ;
        }
        
        //Limit is 100 for now you can change it according to need
        myQuery += ' from ' + SelectedObject + ' LIMIT 100' ;
        
        //Executing the query and fetching results
        ObjectList = Database.query(myQuery) ;
    }
}

Once user selects any object from the first picklist, filed picklist will be populated with all the field labels related to that object. Note, it's a multi-select picklist so user can select multiple fields. Once fields are selected and "Show Table" is clicked, page block table will display the field values (selected in field picklist) of all records (limit is 100 right now, you can change it according to your need).

There are some extra checks that needs to be implemented in code like "isQueryable" etc..

Sep 25, 2012

Creating Public Web-Service in Salesforce

We all are familiar with web services and we often use them. Now let's talk about other side of using web services by making them public so I don't need any authentication/passwords/SessionIds etc.

Recently I need to create a web service so it can used in a mobile app. Most of us know about Mobile SDK, REST, oAuth etc.. but in all I need to intake the credentials of salesforce organization to get access token or if am using web services then to get the session Id. But think about it, why end user will be concerned with the back-end/database? So all we need is a public web service which can be called to process our request.

So follow these simple steps:

1) Create a web service like this

global class DemoClass
{
    webService static string Method()
    {
        return 'DoSomething' ;
    }
}

2) Go to Site > Setup > App Setup > Develop > Sites > Select your Site > Give access of class "DemoClass" to site profile

3) Extract WSDL of your class, go to your class and then click "Generate WSDL". Now all we need to change the SOAP address.

Lets say, this is a snippet of my WSDL



Now we need to change the highlighted code like this:

This is the location:
https://ap1-api.salesforce.com/services/Soap/class/ankit/DemoClass

And our site URL is:

So our final location will be:
http://ankitarorasite-developer-edition.ap1.force.com/services/Soap/class/ankit/DemoClass

Now you can use this location in your WSDL and there will be no need of getting any access tokens or session Ids. Happy Coding.

Aug 23, 2012

Salesforce Platform Developer User Group

Recently Salesforce took an initiative to start developer user groups in India. The goal of developer user group program is to build an enthusiastic, self-sustaining community that enables members to be more successful with Salesforce, and helps to build an army of heroes willing to give testimony to success in the cloud.

Journey begins with New Delhi Salesforce Platform Developer Meetup where I was invited as a guest speaker. There I met "Kavindra Patel" who is behind all this, developer relationship manager at Salesforce. His mindset was very clear and focused on how to get the ball rolling.

I requested him to start a meetup in Jaipur and the immediate words from him was "Go Big". After New Delhi Salesforce organized Developer Hands-On Workshop in Hyderabad, Pune and Bangalore. From there Kavindra pick 8-9 leaders from different regions of India to start the Developer User Group. Here is the complete list, please join the group which is near to your place.

Now it's turn of Jaipur Salesforce Platform Developer User Group Meetup. Luckily am the leader of this group and would request all who are near by Jaipur to join this group. Our inaugural meeting is on 2nd Sept 2012, please RSVP here. There are some awesome technical sessions lined up like "Heroku, Ruby and Force.com Integration" and "Streaming APIs Working Demo". You can get the complete agenda from here. Also join us on LinkedIn, Facebook and Meetup for updates.

Thanks to Kavindra Patel and April Kyle Nassi who helped me to setup a meetup account and will be sending awesome goodies (Caps,T-Shirts,Books etc..) for Cloud Trivia.

Also would like to thank my speakers in inaugural meetup Amit Jain and Deepak Raj. They are also helping me to organize the event, and their contribution is appreciable.

Jul 30, 2012

Is There Better Way To Get Last Date Of Fiscal Quarter?

Recently it was requested to get the "Last Date" of present Fiscal Quarter. For e.g. if "Fiscal Year Start Month" is set to January (Setup > Administration Setup > Company Profile > Fiscal Year) and present month is Feb then date returned should be "31 March 2012"


SOQL is not the option as in the end I need to get the Date so after lot of brain storming end up with this solution, if this is not the best solution then other solutions suggestions are most welcomed.


So here is my apex method which returns me the last date of present fiscal quarter


//Returns last date of present fiscal quarter
public Date LastDateofCurrentFQ()
    {
        // Info : There are 4 Fiscal Quarter FQ( each of 3 months) in fiscal year 
        Organization  org = new Organization() ;
        org = [select FiscalYearStartMonth from Organization where id=:Userinfo.getOrganizationId()];
        Integer FiscalYearStartMonthIndex = org.FiscalYearStartMonth ; 

        // Month Index like january : 1 , february: 2 and so on 
        Integer CurrentMonthIndex = system.today().month();

        if(CurrentMonthIndex < FiscalYearStartMonthIndex )
            CurrentMonthIndex  = 12+ CurrentMonthIndex ;

        Integer DifferenceofBothMonths = CurrentMonthIndex - FiscalYearStartMonthIndex  ;
        Integer CurrentFiscalQuarterLastMonth  = 0; 

 if(0 < = DifferenceofBothMonths && DifferenceofBothMonths <= 2 ) //For first quarter
            CurrentFiscalQuarterLastMonth = FiscalYearStartMonthIndex  +2 ; 
        else if( 3 <= DifferenceofBothMonths && DifferenceofBothMonths <= 5) //For second quarter 
            CurrentFiscalQuarterLastMonth = FiscalYearStartMonthIndex  +5 ;
        else if( 6 <= DifferenceofBothMonths && DifferenceofBothMonths <= 8) // For third quarter
            CurrentFiscalQuarterLastMonth = FiscalYearStartMonthIndex  +8 ;
        else if( 9 <= DifferenceofBothMonths && DifferenceofBothMonths <= 11) // For fourth quarter
            CurrentFiscalQuarterLastMonth = FiscalYearStartMonthIndex  +11 ;

        if(CurrentFiscalQuarterLastMonth > 12)
            CurrentFiscalQuarterLastMonth  = CurrentFiscalQuarterLastMonth  - 12 ;         

        Date firstDateOFyear = date.newInstance(system.today().year(), 1, 1);
        Date LastDateofCurrentFQ  = date.newInstance(system.today().year(), 1, 1); 
        LastDateofCurrentFQ   = firstDateOFyear.addMonths(CurrentFiscalQuarterLastMonth).addDays(-1) ;
        return LastDateofCurrentFQ ;        
    }

Code is self explanatory, still if anything is not clear do reach me out.

New Delhi Salesforce Platform Developer User Group Meetup — My Experience

My experience from inaugural Salesforce Platform Developer User Group Meetup held in Noida (New Delhi) - on SFDC blogs:


http://blogs.developerforce.com/developer-relations/2012/07/new-delhi-salesforce-platform-developer-user-group-meetup.html

Will be organizing Salesforce Platform User Group in Jaipur, please join LinkedIn group for more updates.

http://www.linkedin.com/groups/Salesforce-Platform-Developer-User-Group-4538959

Jul 27, 2012

Please Remove The System Objects From My sObject List

Question is "Can I remove the system objects from list returned by describe?"

I need to identify on which all objects I can create approval process. First and only thought is to use describe and get the list of sObjects, but the problem is describe returns too many other objects on which we can not create approval process like "campaignfeed", "caseteamrole" etc.. So what is the use of showing them all. Why not we can show the list of only those object which are displayed when we create approval from native UI?



Here is the solution for this big time problem. Use this apex code to get the sObject List (use describe in a smart way)

public class ApprovalEnabledObjectsController
{
    //List displayed on UI
    public List<selectoption> supportedObject {get; set;}
    
    //Constructor
    public ApprovalEnabledObjectsController()
    {
        //Initialize
        supportedObject = new List<selectoption>() ;
        
        //Get only reference to objects
        for(Schema.SObjectType item : ProcessInstance.TargetObjectId.getDescribe().getReferenceTo())
        {
            //Excluding custom setting objects
            if(!item.getDescribe().CustomSetting)
            {
                //Adding to list
                supportedObject.add(new SelectOption(item.getDescribe().getLocalName().toLowerCase() , item.getDescribe().getLabel() ));
            }
        }
        
    }
}


Visualforce Page (Test page to show the picklsit)



    
        
    




Special thanks to Amit Jain who helped me with this :-)

May 30, 2012

Update Record From Formula Field

Recently an interesting implementation forced me to write this post, and may be many of you are already aware of this. There is a related list where I need to show a formula field, and on click of that field I need to change the status of that record.

Say case is related to account, and they are displayed in a related list on account. Now I want to change the status of any case which is related to an account. One way is to click on the case "edit", change the status and save it. I don't want to do this as it takes time and more button clicks. Another way is to provide a formula field as a hyperlink, and when that link is clicked status should be changed.

So for this create a formula field on Case ("UpdateStatus" for the reference) which will be a hyperlink and it will execute an visualforce page like this :

HYPERLINK("/apex/UpdateStatus?RecId=" + Id ,"Click To Change Status","_top")


Now add this formula field in case related list on account page layout, like this :



Now it's time to write a Visualforce page, so here is the code :


    
    
    
    



I know this is not the best approach to go with, and am open for any other solutions or findings.

May 15, 2012

Static Resource URL in Apex

Question is how to get the Static Resource's URL in Apex, so below is the function which will return the relative URL (also supports namespace-resources)


public class StaticResourceURL
{
    //Pass the resource name
    public static String GetResourceURL(String resourceName)
    {
        //Fetching the resource
        List resourceList = [SELECT Name, NamespacePrefix, SystemModStamp FROM StaticResource WHERE Name = :resourceName];
                            
        //Checking if the result is returned or not
        if(resourceList.size() == 1)
        {
           //Getting namespace
           String namespace = resourceList[0].NamespacePrefix;
           //Resource URL
           return '/resource/' + resourceList[0].SystemModStamp.getTime() + '/' + (namespace != null && namespace != '' ? namespace + '__' : '') + resourceName; 
        }
        else return '';
    }
}


Use this in debug logs to verify :


System.debug(':::: ' + StaticResourceURL.GetResourceURL('StaticResourceName')) ;


*Please change the "StaticResourceName" with your Static resource name in above line

Jan 15, 2012

Integrating Google Maps in Salesforce

Requirement is to show the location of my Account on Google Maps. It looks difficult but actually it is very simple to implement.


Just create a new visualforce page with this code
<apex:page standardController="Account">

<script src="http://maps.google.com/maps?file=api">
</script>

<script type="text/javascript">

var map = null;
var geocoder = null;

var address = "{!Account.BillingStreet}, {!Account.BillingPostalCode} {!Account.BillingCity}, {!Account.BillingState}, {!Account.BillingCountry}";

function initialize() {
if(GBrowserIsCompatible())
{
  map = new GMap2(document.getElementById("MyMap"));
  map.addControl(new GMapTypeControl());
  map.addControl(new GLargeMapControl3D());
  
  geocoder = new GClientGeocoder();
  geocoder.getLatLng(
    address,
    function(point) {
      if (!point) {
        document.getElementById("MyMap").innerHTML = address + " not found";
      } else {
        map.setCenter(point, 13);
        var marker = new GMarker(point);
        map.addOverlay(marker);
        marker.bindInfoWindowHtml("Account Name : <b><i> {!Account.Name} </i></b> <br/> Address : "+address);
      }
    }
  );
}
}
</script>


<div id="MyMap" style="width:100%;height:300px"></div>
<script>
    initialize() ;
</script>

</apex:page>
As you can see that I have used standard controller so you need to pass the account Id in URL. Let's say if the page name is "GoogleMaps" then the URL will look something like this : ".../apex/GoogleMaps?id=YOUR_ACCOUNT_ID".






When you click on the balloon it will show you the Account name and the address, you can change it according to your need by changing the code of line "marker.bindInfoWindowHtml"


Use this page as in line visualforce page on native layout and enjoy the Google maps with Salesforce.


References
http://code.google.com/apis/maps/documentation/webservices/
http://code.google.com/apis/maps/index.html