February 1, 2010

Visualforce Salesforce jquery Ajax how to ?

Edits - Nov 2011

This post was written long back in Feb 2010, since then force.com platform is drastically upgraded/changed. The illustration indicated in the post below can be achieved very easily using new platform features like Javascript Remoting.

So if you are planning to use JSON with jquery/javascript, more fun way to achieve the same is remoting, this post is a good guide to start with remoting & jquery :

 http://www.tgerm.com/2011/03/javascript-remoting-jquery-templates.html

 

Abstract

This post is for those who want to make AJAX calls in visualforce using 3rd party JavaScript frameworks like jquery, yui , dojo etc. Though most the times the built in visual force Ajax works pretty well and you don’t need to make your hands dirty by doing this. But but but, there are couple of occasions when its required for ex.

  • You are working on a complex DOM structure i.e. there is nesting of HTML elements in a manner not easy to deal with Visual force tags.
  • You want to update the DOM client side, this requires some Ajax calls to query server side data.
  • Visualforce Ajax gives you a way to do this by calling “rerender”, but you want more control on request and response data.

Design

Following is the high level design of custom Http request response in salesforce

image

So this design comprises of following elements

  1. A dedicated Visualforce page for receiving inbound Ajax http requests. Lets call this page “AjaxResponder
  2. This page can return either “JSON” or “XML” response.
  3. For doing all server side logic an Apex Controller is required that will do the SOQL/SOQL queries. Lets call this “AjaxRespController
  4. A client page to test and do all the Ajax calls. Lets call this “AjaxClient

Implementation (Apex Visualforce code)

We will start with the Server Side code first i.e. AjaxResponder(Visualforce Page) and AjaxRespController (Apex Controller). At last you can find code for the Ajax client page.

AjaxResponder(Visualforce):

Simple visualforce page. Please note that you need to add following apex:page headers. This is because we don’t want any other HTML markup from salesforce in Ajax response.

  • showHeader = false
  • standardstylesheets = false
  • sidebar = false

Apart from this you need to set the content type for JSON response, so add the header contentType="application/x-JavaScript; charset=utf-8". For printing JSON text in visualforce page, just create a string attribute in your controller, for this demo I created “result”, and add this to VF code like this {!result}.

<apex:page controller="AjaxRespController"  action="{!doSearch}"
contentType="application/x-JavaScript; charset=utf-8" showHeader="false" standardStylesheets="false" sidebar="false">
{!result}
</apex:page>

AjaxRespController (Apex Controller):

Controller will check the Ajax request parameters and will do the SOQL query stuff. In the code snippet below doSearch() method is called on Ajax call. We have used JsonObject, this is a class adopted from json.org by Ron Hess. You can get it from here. Apart from this there is a getter method called “getResult” it returns the JSON response back to visualforce.

public class AjaxRespController {
    public JsonObject json {get;set;}
    
    /** invoked on an Ajax request */    
    public void doSearch() {
        Map<string,string> params = ApexPages.currentPage().getParameters();
        json = new JsonObject();
        
        // Do SOQL query to see if there are any records !
        List<Contact> records = getRecords(params.get('q'));
        
        if (!records.isEmpty()) {
            // Jsonify the results !
            List<JSONObject.value> values = new List<JSONObject.value>(); 
            for (Contact c : records) {
                JSONObject cjson = new JSONObject();
                cjson.putOpt('name', new JSONObject.value(c.Name));
                cjson.putOpt('email', new JSONObject.value(c.email));
                values.add(new JSONObject.value(cjson));
            }   
            json.putOpt('contacts', new JSONObject.value(values));
            
        }
    }
    
    // Does the SOQL query, using Ajax request data
    public List<Contact> getRecords(String contactName) {
        List<Contact> records = new List<Contact>();
        if (contactName != null && contactName.trim().length() > 0){
            // Protect from SOQL injection            
            String contactNameToFilter = '%' + contactName  + '%';
            records = [select id, name, email from contact where Name like :contactNameToFilter];
            
        }   
        return records;      
    }    

    // Returns the JSON result string
    public String getResult() {
        return json.ValuetoString();
    }
    
}

Ajax Client (Visual force):

This page is one that presents the user interface to query the results via custom Ajax. The code below is simple markup to do Ajax calls and show JSON response. Please note here in code that to make Ajax calls work, you need to pass an extra param "core.apexpages.devmode.url" with value '1'. This is required because without this param the visualforce page is opened in an iframe and you get the iframe code wrapped in other crappy html.

<apex:page showHeader="true" standardStylesheets="true" >

    <script
        src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"
        type="text/JavaScript" />
    
    
    <script type="text/JavaScript">
    function search() {
        $("#status").html(
                "Making a Jquery Ajax Request to '{!$Page.AjaxResponder}'");

        // Make the Ajax Request
        $.getJSON("{!$Page.AjaxResponder}", {
            "core.apexpages.devmode.url" :'1',
            "q" :$('#query').val()
        }, function(data) {
            $("#response").html(JSON.stringify(data));
        });

        $("#status").html("Ajax Request Completed !");
    }
</script>

    <apex:sectionHeader title="Ajax Client Demo" />

    <apex:pageblock >
            <apex:pageBlockSection title="Query Console">
                <form id="qform">Query String <input type="text" id="query" />
                <input type="button" onclick="search()" value="Search Contacts " /></form>
            </apex:pageBlocksection>

            <apex:pageBlockSection title="Ajax Console">
                <h1>Status</h1> 
                <pre id="status" style="font-size: 16px" />
                    
                <h1> JSON Response </h1> 
                <div id="response" style="font-size: 16px;width: 300px;font-family: monospace; font-stretch: expanded" />
        </apex:pageBlocksection>
    </apex:pageblock>

</apex:page>

Here is this UI in action

Here is the VIDEO SCREENCAST !

You can copy all the code snippet above and run it directly on your salesforce org. Just replace “[NODE]” in following URL by yours.

https://[NODE].force.com/apex/AjaxClient