Andy in the Cloud

From BBC Basic to and beyond…

Super ListView Viewer using Winter’15 ListView API


Salesforce continues its drive to push out great platform API’s, while Winter’15 was a little lighter than usual, the List View API did catch my eye! It’s available currently in SOAP and REST flavours, sadly as yet no Apex, though I’ve seen Salesforce follow up in later releases with Apex support, so fingers crossed! This omission didn’t stop me exploring the REST variant via Visualforce and JQuery!

I’ve written a few applications that leverage List Views to provide a readily available filter criteria for various uses. One approach used the StandardSetController in Apex (via the setFilterId method) and another by reading the object definition (using Metadata API), parsing the List View definition and building my own SOQL query! This later strategy can now be replaced with the new List View API, as amongst giving you the List View definition and the records behind it, you also get hold of the SOQL query Salesforce uses as well!

The REST API version provides the following resources to call..

  • /services/data/v32.0/sobjects/Account/listviews – Lists the List Views associated with the object and their Id’s (click the link to try it out in Developer Workbench!). Documentation here.
  • /services/data/v32.0/sobjects/Account/listviews/{Id}/describe – Returns the definition of the List View and the SOQL! Documentation here.
  • /services/data/v32.0/sobjects/Account/listviews/{Id}/results – Returns the column definitions of the List View and the records it returns. Documentation here.

While exploring the SOQL used by ListViews, i noticed something i had not seen before in the SOQL syntax, the USING SCOPE clause, also new to Winter’15. Recently View Accounts and My Accounts views leverage this new clause…

SELECT name, site, billingstate, phone, tolabel(type), 
  owner.alias, id, createddate, lastmodifieddate, systemmodstamp 
FROM Account 

The above shows ‘mru’ and the following example shows ‘mine’…

SELECT name, site, billingstate, phone, tolabel(type), 
  owner.alias, id, createddate, lastmodifieddate, systemmodstamp 
FROM Account 

The documentation is a bit weak presently on the other values, this knowledge base article, lists Everything, Mine, Queue, Delegated, MyTerritory, MyTeamTerritory or Team, but not MRU at present.

So to give these API’s a better shake down i decided to flex my JavaScript side this time, knowing that its possible to call these API’s from the Visualforce Domain without issue, its a matter of making a JavaScript call and interpreting the results. Thus Super ListView Viewer was born! With a little help from the frankly amazing JQuery plugin known as DataTable, which replicates as far as I can see the standard List View UI and then some!

This page allows you to select any object and if it has associated List View’s view them!


JQuery provices some excellent AJAX support, this code reads the SOQL query and displays it on the page…

// List View describe to take a look at the SOQL!
	url : '/services/data/v32.0/sobjects/' + objectName + '/listviews/' + listViewId + '/describe', 
	headers : { 'Authorization' : 'Bearer {!$Api.Session_ID}' },
	datatype : 'json', 
	success : function(data, textStatus, jqXHR) {					

This code builds a regular HTML table and then in a single line turns it into the amazing DataTable, I was quite amazed when i added this library, seriously cool!

// Call the List View API to get the results (also includes column definitions)
	url : '/services/data/v32.0/sobjects/' + objectName + '/listviews/' + listViewId + '/results', 
	headers : { 'Authorization' : 'Bearer {!$Api.Session_ID}' },
	datatype : 'json', 
	success : function(data, textStatus, jqXHR) {					

		// Clear current List View info

		// Create the table and add columns
		var table = $('<table></table>');
		var thead = $('<thead></thead>');
		var theadtr = $('<tr></tr>');					
		$.each(data.columns, function(index, column) {
				theadtr.append($('<th>' + column.label + '</th>'));

		// Add the rows
		var tbody = $('<tbody></tbody>');
		$.each(data.records, function(rowIndex, record) {
			var tbodytr = $('<tr></tr>');					
			$.each(record.columns, function(colIndex, column) {
					tbodytr.append($('<td>' +
					 (record.columns[colIndex].value!=null ? 
					  record.columns[colIndex].value : '') + '</td>'));

		// Enhance this boring old HTML table with JQuery DataTable!
		var dataTable = table.DataTable();

You can find the full source code for this here. Of course if you had need to call this API from Apex, you can make an outbound HTTP callout, after having set up the Remote Site to allow Salesforce to call itself…


15 thoughts on “Super ListView Viewer using Winter’15 ListView API

  1. Is it possible to select a list from this page and pass it to a StandardSetController? What would that look like?

  2. Pingback: Setup Audit Trail API in Winter’16 | Andy in the Cloud

  3. Can a subset of objects be used instead of all objects in the Object drop down?

  4. In standard list views we get hyperlinks such as lookup fields and record #s. But this does not show those fields as hyperlinked. I guess I have to do Hyperlink Formula fields to show those?

  5. Is it possible to get more fields in the query in the describe call? Or is it a fixed set of fields that are returned.

  6. Hi Andrew, great work! I’m facing an interesting problem, and I’d appreciate your view on solutions.

    I need to display listview results for a particular Account. Say I select the ‘My Opportunities’ ListView, I want to see Records that match this ListView that are associated with a particular account (maintaining the fields, and order defined by the ListView).

    My current solution involves modifying the soql query to append ‘WHERE Account.Id = %s’, which works for simple ListViews. But as soon as I try to load a more complex ListView with a more complex query, the query modification slips up. I’ve tried to look for javascript SQL parsers, but they seem to be immature and I wouldn’t want to count on them in a production environment, as SOQL can get seriously complex.

    Another solution would be to query for all the records, and filter the results after receiving them, but with large Salesforce instances this becomes ineffective, especially when taking into account query limits.

    I’d really appreciate your input on an interesting problem! How would you go about solving this?

Leave a Reply to Andrew Fawcett Cancel reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s