Thursday, July 6, 2017

Web page : Ways to resolve "Collection size xxxx exceeds maximum size of 1000" on VF page

Visualforce pages are not designed to display more than 1000 records in UI. So if you have controller method which returns more than 1000 records and you are displaying the records on UI, then you will receive error "Collection size xxxx exceeds maximum size of 1000"  where xxxx is number of records returned by your controller method.


So now if you have to display more than 1000 records on UI, then you can use below options:
  • Use @ReadOnly annotation on method or on page attribute.

As per Salesforce Documetation:

Normally, queries for a single Visualforce page request may not retrieve more than 50,000 rows. In read-only mode, this limit is relaxed to allow querying up to 1 million rows.

In addition to querying many more rows, the readOnly attribute also increases the maximum number of items in a collection that can be iterated over using components such as <apex:dataTable>, <apex:dataList>, and <apex:repeat>. This limit increased from 1,000 items to 10,000.

  • You can restrict the number of records returned by method and provide pagination option using controller method.

For this you have to write the logic in controller and every time you will send request to server in order to render the page.


You can also jquery datatables and pass the JSON data to it to create table for you and you will get pagination, sorting or filtering of records on client side itself which will be very quick.

So we will pass more than 1000 records as a JSON to VF page and by using jQuery, we can build table.

Below is sample apex class and VF page code:
public class CollectionLimitController {
public List<Account> collectionSizeVariable{get;set;}
public String AccountInformationString {get;set;}
public CollectionLimitController(){
collectionSizeVariable = new List<Account>();
for(integer i=0;i<50007;i++){
collectionSizeVariable.add(new Account(name='sunil'+i, type='Prospect', Industry='IT'));
}
datasetForTable dataSet =new datasetForTable();
list<list<String>> dataValues=new list<list<String>>();
list<list<String>> columnsLabels=new list<list<String>>();
columnsLabels.add(new List<String>{'Account name'});
columnsLabels.add(new List<String>{'Type'});
columnsLabels.add(new List<String>{'Industry'});
for(Account sb: collectionSizeVariable){
list<String> fieldvalues = new List<String>();
if(sb.name != null && sb.name != ''){
fieldvalues.add(sb.name );
}else{
fieldvalues.add('');
}
if(sb.Type != null && sb.Type != ''){
fieldvalues.add(sb.Type);
}else{
fieldvalues.add('');
}
if(sb.Industry != null && sb.Industry != ''){
fieldvalues.add(sb.Industry);
}else{
fieldvalues.add('');
}
dataValues.add(fieldvalues);
}
dataSet.data = dataValues;
dataSet.columns = columnsLabels ;
AccountInformationString = JSON.serialize(dataSet);
system.debug('************AccountInformationString:'+AccountInformationString);
}
public class datasetForTable{
public List<List<String>> columns;
public List<List<String>> data;
}
}
<apex:page controller="CollectionLimitController" sidebar="false">
<head>
<apex:includescript value="https://code.jquery.com/jquery-1.11.1.min.js" / >
<apex:includescript value="https://cdn.datatables.net/1.10.4/js/jquery.dataTables.min.js" />
<apex:stylesheet value="https://cdn.datatables.net/1.10.4/css/jquery.dataTables.css" />
<apex:includescript value="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js" / >
<apex:includescript value="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" />
<script>
var sk= $.noConflict();
var tableData = '{!AccountInformationString}';
//alert('tableData :'+tableData );
sk(document).ready(function() {
tableData =tableData .replace(/(&quot\;)/g,"\"")
tableData = tableData .replace(/(&lt\;)/g,'<').replace(/(&gt\;)/g,'>').replace(/(&#39\;)/g,'\'').replace(/(&amp\;)/g,'&');
var jsonData = JSON.parse(tableData)
//alert('*****jsonData :'+jsonData );
console.log(jsonData);
generateTable(JSON.parse(tableData));
});
function generateTable(jsonData){
var tableHeaders="";
$.each(jsonData.columns, function(i, val){
tableHeaders += "<th>" + val + "</th>";
});
$("#tableDiv").empty();
$("#tableDiv").append('<table id="displayTable" class="display" cellspacing="0" width="100%"><thead><tr>' + tableHeaders + '</tr></thead></table>');
$("#displayTable").dataTable(jsonData);
}
</script>
</head>
<body>
<div id="tableDiv" style="width:100%;overflow: auto;"></div>
</body>
</apex:page>

VF page Output (Displaying more than 50000 records)



If you have to dispaly hyperlink on account name, then modify the account name value before adding it to fieldvalues list at line number 19 in apex class as shown below:
sb.name= '<a href=\'/' + sb.id + '\'  target=\'_blank\'>' + sb.name+ '</a>';



This will display hyper link to account record. In my example code, I am adding new records to list so id are not present. If you are using query to add records in account list, then you can use above code snippet to show hyperlink.

No comments:

Post a Comment