apex

extjs & visualforce (part 2), JSON this time

Let me preface this post by stating that the following is merely a proof of concept and should not necessarily be implemented into a production org. The pagination demonstrated below is not fit for large datasets and may result in unexpected behavior!

Rich Waters’ comment on my first post re: Ext JS & visualforce got me thinking about the possibilities of leveraging JSON in Ext JS components within Visualforce, so I implemented a paging grid, similar to this example provided by Ext JS. OK, enough of the formalities, I suppose people want to see what kind of development ensued:

First, the product, a JSON-based Ext JS paging grid:

Now, for the magic behind the grid, the JSON file (a Visualforce page called “Json_test”):


<apex:page contentType="text/html" showHeader="false" controller="Json_File" >
	<apex:outputText value="{!json}" />
</apex:page>

The controller (spits out the JSON):


public class Json_File {

	public string json {get;set;}

	public Json_File() {
        opportunity[] opps = new opportunity[]{};

	integer start = 0;
	integer pageSize = 10;

	if (ApexPages.currentPage().getParameters().get('start') != null &amp;amp;amp;amp;&amp;amp;amp;amp; ApexPages.currentPage().getParameters().get('limit') != null) {
		start = integer.valueof(ApexPages.currentPage().getParameters().get('start'));
		pageSize = integer.valueof(ApexPages.currentPage().getParameters().get('limit'));
	}

        string jsonRecordsString = '';

        integer i = 1;
        integer j = 0;

        for (Opportunity o : [Select id, name, stagename, closedate from opportunity order by name limit 1000]) {
			if (j >= start) {
				if (i <= pageSize) {
					jsonRecordsString += '{';
					jsonRecordsString += '"id":' + '"'+o.id+'",';
					jsonRecordsString += '"name":' + '"'+o.name+'",';
					jsonRecordsString += '"stagename":' + '"'+o.stagename+'",';
					jsonRecordsString += '"closedate":' + '"'+o.closedate+'"';
					jsonRecordsString += '},';
					i++;
				}
			}
			opps.add(o);
			j++;
        }

		string jsonString = '({"total":"'+opps.size()+'", "results":[' + jsonRecordsString + ']})';
        jsonString = jsonString.replaceAll(',]',']');
        this.json = jsonString;
	}
}

Finally, the grid itself (from the Visualforce page embedded above in this post):

*It’s important to note that this Visualforce page does not have a controller; the JsonStore provides the reference needed (url) [see below] to access the future backend of the grid.


<script type="text/javascript">
	var opportunity_grid;

	Ext.onReady(
		function() {
			//prevents mixed content message in ie
			Ext.BLANK_IMAGE_URL = '/s.gif';
			Ext.SSL_SECURE_URL = '/s.gif';
			render_queue();
		}
	);

	function render_queue() {
		// create the data store
		var store = new Ext.data.JsonStore({
			totalProperty: 'total',	// total data, see json output
			root: 'results',	// see json output
			url: 'http://crmmanager-developer-edition.na6.force.com/test/Json_test',
	        fields: [
	           {name: 'id'},
	   			'name', 'stagename', 'closedate'
       		]
   		});

		var pagingBar = new Ext.PagingToolbar({
	        pageSize: 10,
	        store: store,
	        displayInfo: true,
	        displayMsg: 'Displaying opportunities {0} - {1} of {2}',
	        emptyMsg: "No opportunities to display"
	    });

		var gridView = new Ext.grid.GridView({
				forceFit: true
		}); 

	    opportunity_grid = new Ext.grid.GridPanel({
	        store: store,
	        columns: [
	            {header: "name", width: 150, dataIndex: 'name', sortable: true},
	            {header: "stage", width: 150, dataIndex: 'stagename', sortable: true},
	            {header: "close date", width: 150, dataIndex: 'closedate', sortable: true}
	        ],
	        width:580,
	        height:300,
	        loadMask: true,
	        bbar: pagingBar,
	        view: gridView,
	        layout: 'fit'
	    });
		try {
			opportunity_grid.render('opportunity_grid');
		} catch(e){}	

		store.load({params:{start:0, limit:10}});
	}
</script>

As you can see, the Json_File controller accepts two params (start, pageSize), which are sent from the store in store.load() to manage the index of the query and the number of records returned. Unfortunately, Salesforce does not provide an “INDEX” keyword in SOQL, which would make this pagination much more “resource respectful” (each time page up/page down is called from the paging grid, we receive a full dataset from Salesforce which, as you might guess, can be dangerous for tables with more than a thousand records).

I looked into the possibility of leveraging StandardSetController, but given the out-of-box architecture of the paging grid, we’d still be calling our JSON controller each time the grid was “paged”, which effectively calls the entire dataset.

I’m open to ideas, so please weigh in.

EDIT: the source for the above example…
ExtJs_Json_Grid.page
Json_Controller.cls
Json_test.page

You may also like:

Banter

10 comments for “extjs & visualforce (part 2), JSON this time”

  1. Joe,

    Nice work. Can you post the full pages for this example. I tried to recreate this example but can’t get it to display any records. The Json_test page retrieves records and displays the Json as expected. However the grid page only renders the grid and the pagingtoolbar but no records.

    Thanks!

    Posted by Matt Ammer | April 24, 2009, 7:26 pm
  2. Looks nice. I’m having a similar problem as Matt when I try to recreate.

    Namely, the page fails with this error:

    System.NullPointerException: Argument 1 cannot be null. Class.Json_File.: line 8, column 81 External entry point 

    Which I assume means that the start value in this call is undefined:

    integer.valueof(ApexPages.currentPage().getParameters().get('start'));

    Any idea what could be wrong?

    Posted by Toryvald | May 6, 2009, 3:30 pm
  3. see the updated source…

    Posted by joe | May 13, 2009, 4:50 pm
  4. Nice work. Can you post the full pages for this example. I tried to recreate this example but can?t get it to display any records. The Json_test page retrieves records and displays the Json as expected. However the grid page only renders the grid and the pagingtoolbar but no records.

    Thanks!

    Posted by arun pandey | May 28, 2009, 8:56 am
  5. sorry for the delay, see source at the bottom of the post

    Posted by joe | May 30, 2009, 12:18 pm
  6. where joe ,u have written see source at the bottom but their is nothing there ,pls help me i am feeling helpless pls .u have done a wonderful work but pls help by posting the solution of my problem

    Posted by arun pandey | June 1, 2009, 4:31 am
  7. Hi Joe,

    I did the same thing as you but it is not working.
    After login on SF Dev org and try to access the VF page for the very first time, SF redirects my request to another server (to validate my auth?!) and then send me back to the original address, where my JSON data is publishied.
    Because of this redirection the JS code doesn’t work.

    Do you know how to solve it?

    Best regards

    Posted by Paulo Castro | October 8, 2009, 8:07 pm
  8. BTW, after this first redirection the following request works fine and the JS execute perfectly.

    Posted by Paulo Castro | October 8, 2009, 8:08 pm
  9. Grid page only renders the grid and the pagingtoolbar but no records

    Posted by NIraj Nayan | October 31, 2009, 4:45 am
  10. [...] which field we want to display when generating the autocomplete. See the community boards and Joe Ferraro’s article for some more cool examples of generating [...]

    Posted by Transform your Visualforce Lookups into JQuery Autocompletes « d3developer | May 8, 2010, 11:50 am

Post a comment