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 USING SCOPE mru ORDER BY Name ASC NULLS FIRST, Id ASC NULLS FIRST
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 USING SCOPE mine ORDER BY Name ASC NULLS FIRST, Id ASC NULLS FIRST
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! $.ajax({ url : '/services/data/v32.0/sobjects/' + objectName + '/listviews/' + listViewId + '/describe', headers : { 'Authorization' : 'Bearer {!$Api.Session_ID}' }, datatype : 'json', success : function(data, textStatus, jqXHR) { $('#soql').text(data.query); } });
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) $.ajax({ 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 $('#listview').empty(); // Create the table and add columns var table = $('<table></table>'); var thead = $('<thead></thead>'); var theadtr = $('<tr></tr>'); table.appendTo('#listview'); table.append(thead); thead.append(theadtr); $.each(data.columns, function(index, column) { if(!column.hidden) theadtr.append($('<th>' + column.label + '</th>')); }); // Add the rows var tbody = $('<tbody></tbody>'); table.append(tbody); $.each(data.records, function(rowIndex, record) { var tbodytr = $('<tr></tr>'); tbody.append(tbodytr); $.each(record.columns, function(colIndex, column) { if(!data.columns[colIndex].hidden) 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…
Enjoy!
October 30, 2014 at 7:55 pm
Is it possible to select a list from this page and pass it to a StandardSetController? What would that look like?
November 1, 2014 at 10:53 am
It is not possible to pass records into a StandardSetController, but you can initialise it with the ListView ID and then its getRecords method will return the same information. http://salesforce.stackexchange.com/questions/3561/standardsetcontroller-list-instatiation-and-setfilterid/3604#3604
Pingback: Setup Audit Trail API in Winter’16 | Andy in the Cloud
September 16, 2016 at 3:33 pm
Can a subset of objects be used instead of all objects in the Object drop down?
September 17, 2016 at 10:45 am
Yes, its just a sample, you can take the code and filter how you wish.
September 20, 2016 at 4:31 pm
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?
September 21, 2016 at 8:52 pm
Yeah probably, it was not ment to be fully like for like tbh, but gets close! 😉
September 22, 2016 at 9:41 pm
I am getting max list view records of 25. I should show over 25 records in the list view. Thoughts?
September 23, 2016 at 3:53 am
Looks like the record limitation is 2000 on the result 😦
September 26, 2016 at 9:02 am
Yes this appears to a general limit for List Views in the UI and API. It does give you the SOQL though for the List View, so you can then use that with the regular Salesforce REST SOQL API and the queryMore convention. https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_listviewdescribe.htm
February 17, 2017 at 2:25 pm
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.
February 18, 2017 at 5:49 pm
The fields are defined by the user when the y setup the ListView.
April 13, 2017 at 5:15 pm
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?
April 15, 2017 at 4:53 am
Thanks! Try taking the entire expression after the WHERE clause and wrapping it braces then add ‘ AND Account.Id = %s’ https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_conditionexpression.htm “You can use parentheses to define the order in which fieldExpressions are evaluated. For example, the following expression is true if fieldExpression1 is true and either fieldExpression2 or fieldExpression3 are true:”
April 16, 2017 at 11:00 am
Thanks for your response! This is a good solution which I think will work for the majority of queries – I’ll let you know how it works out!