Best Practice View State 3:
This is a good example to reduce view state using visualforce remoting. You can observe following example results by chrome developer inspect (Ctrl+Shft+I) .Main difference between a remoting and a actionfunction method call and results.By using remoting you can call method with attributes directly from page where as actionfunction not also the call back function returns only results in remoting but using standard visualforce tags it brings html that you can see below .
a)Remoting:
public with sharing class DF12RemotingController {
@RemoteAction
public static List<Contact> doSearch(String customerLastName) {
// be careful when doing LIKE queries with '%' wildcards on both
// sides of the query term, especially when using non-indexed
// fields, as performance can suffer
customerLastName = '%' + customerLastName + '%';
return [
SELECT Id, FirstName, LastName
FROM Contact
WHERE LastName LIKE :customerLastName
ORDER BY LastName, FirstName
LIMIT 200
];
}
@isTest
private static void testDoSearch() {
List<Contact> control = new List<Contact>();
control.add(new Contact(LastName = 'Smith', FirstName = 'Joe1', Email = 'test@test.test.test.test'));
control.add(new Contact(LastName = 'Smith', FirstName = 'Joe2', Email = 'test@test.test.test.test'));
insert control;
List<Contact> actual = DF12RemotingController.doSearch('Smith');
System.assert(actual.size() == 2, 'There should be two contacts named Smith here.');
}
}
<apex:page controller="DF12RemotingController" docType="html-5.0" showHeader="false" standardStylesheets="false">
<apex:styleSheet value="{!$Resource.AdvVFWebinarCSS}"/>
<apex:composition template="DF12Template">
<apex:define name="pageTitle">DF '12: JavaScript Remoting Example</apex:define>
<apex:define name="header">
<h1 class="pageTitle">Find Customer</h1>
<h4>JavaScript Remoting Example</h4>
</apex:define>
<apex:define name="body">
<input id="searchField" type="text" placeholder="Enter Last Name"/>
<button type="button" onclick="console.log('Step 1: Search button clicked.');DF12Examples.handleButtonClick();">Search</button>
<table cellpadding="0" cellspacing="0">
<thead></thead>
<tfoot></tfoot>
<tbody id="results"></tbody>
</table>
<div class="cheatLinkSeparator">
<a class="cheatLink" href="{!$Page.DF12Action}" title="Open apex:actionFunction Example">apex:actionFunction Example</a>
</div>
</apex:define>
<apex:define name="pageScripts">
<script>
// startTime and endTime are only being created for logging purposes, but
// note that I am initializing their values to Date objects. this is so
// JavaScript doesn't have to guess what kind of variables they are
// (and therefore, doesn't have to change their datatype mid-execution).
// this is a best practice for all JS variable declarations to help with
// performance.
DF12Examples.startTime = new Date();
DF12Examples.endTime = new Date();
// gets called when the 'Search' button is clicked
DF12Examples.handleButtonClick = function() {
console.log('Step 2: JS function handleButtonClick() called.');
DF12Examples.startTime = Date.now();
var searchTerm = document.getElementById("searchField").value;
// call the apex controller method tagged w/ the @RemoteAction annotation.
// the syntax is ControllerName.methodName(methodArguments, jsCallbackFunctionName, options).
// the 'options' argument is optional.
console.log('Step 3: JS function that maps to Apex controller method doSearch(String customerLastName) - via @RemoteAction annotation - called.');
DF12RemotingController.doSearch(searchTerm, DF12Examples.renderResults);
};
// this is the js callback function that will execute when the @RemoteAction method
// in the apex controller is done executing. it will always receive two arguments
// passed from the controller method: 1) the JSON-encoded results, and an 'event'
// object, which tells you if everything went ok on the server side.
DF12Examples.renderResults = function (results, event) {
console.log('Step 4: Results recieved. JavaScript function renderResults() called.');
// if the apex method completed execution, event.status is true.
if (event.status) {
// if there was an exception, you should handle it here.
if (event.type === "exception") {
// do stuff
} else {
// this is the empty <tbody> tag on the page
var container = document.getElementById("results"),
html = [];
for (var i=0, j=results.length; i<j; i++) {
html.push("<tr><td>");
html.push(results[i].LastName + ", " + results[i].FirstName);
html.push("</td></tr>");
}
// this won't work in IE, because IE doesn't handle setting
// innerHTML for <tr> or <tbody> tags. *sigh*. To get this
// working in IE, you'd need to use document.createElement()
// for every DOM node you want to create, then use appendChild()
// to attach them to the correct parent.
container.innerHTML = html.join("");
}
}
DF12Examples.endTime = Date.now();
if (console) {
console.log("elapsed time: " + (DF12Examples.endTime - DF12Examples.startTime) + "ms");
}
};
</script>
</apex:define>
</apex:composition>
</apex:page>
b)Without Remoting:
public with sharing class DF12ActionController {
public String customerLastName { get; set; }
public List<Contact> searchResults { get; private set; }
public void doSearch() {
// be careful when doing LIKE queries with '%' wildcards on both
// sides of the query term, especially when using non-indexed
// fields, as performance can suffer
customerLastName = '%' + customerLastName + '%';
searchResults = [
SELECT Id, FirstName, LastName
FROM Contact
WHERE LastName LIKE :customerLastName
ORDER BY LastName, FirstName
LIMIT 200
];
}
@isTest
private static void testDoSearch() {
Contact c = new Contact(LastName = 'Smith', FirstName = 'Joe');
insert c;
DF12ActionController con = new DF12ActionController();
con.customerLastName = 'Smith';
con.doSearch();
System.assert(con.searchResults.size() > 0, 'Should have found at least one contact');
}
}
<apex:page controller="DF12ActionController" docType="html-5.0" showHeader="false" standardStylesheets="false">
<apex:composition template="DF12Template">
<apex:define name="pageTitle">DF '12: <apex:actionFunction> Example</apex:define>
<apex:define name="header">
<h1 class="pageTitle">Find Customer</h1>
<h4><apex:actionFunction> Example</h4>
</apex:define>
<apex:define name="body">
<apex:form >
<apex:actionFunction name="findMeSomeCustomers" action="{!doSearch}" reRender="customers" oncomplete="DF12Examples.handleActionFunctionCompletion();">
<apex:param name="customerLastName" assignTo="{!customerLastName}" value=""/>
</apex:actionFunction>
<input id="searchField" type="text" placeholder="Enter Last Name"/>
<button type="button" onclick="console.log('Step 1: Search button clicked.');DF12Examples.handleButtonClick();">Search</button>
<apex:outputPanel layout="block" id="customers">
<apex:dataTable value="{!searchResults}" var="sr">
<apex:column >{!sr.LastName}, {!sr.FirstName}</apex:column>
</apex:dataTable>
</apex:outputPanel>
</apex:form>
</apex:define>
<apex:define name="pageScripts">
<script>
// startTime and endTime are only being created for logging purposes, but
// note that I am initializing their values to Date objects. this is so
// JavaScript doesn't have to guess what kind of variables they are
// (and therefore, doesn't have to change their datatype mid-execution).
// this is a best practice for all JS variable declarations to help with
// performance.
DF12Examples.startTime = new Date();
DF12Examples.endTime = new Date();
// gets called when the 'Search' button is clicked
DF12Examples.handleButtonClick = function() {
console.log('Step 2: JS function handleButtonClick() called.');
DF12Examples.startTime = Date.now();
// the JS function findMeSomeCustomers is automatically created for you
// when you use an actionFunction tag (see above). the argument
// being passed into this function corresponds to the param tag
// nested inside the actionFunction tag.
console.log('Step 3: JS function that maps to Apex controller method doSearch() - via apex:actionFunction tag - called.');
findMeSomeCustomers(document.getElementById('searchField').value);
};
// gets called when the apex controller method that is bound to the
// actionFunction tag's 'action' attribute (in this case, 'doSearch()')
// completes processing
DF12Examples.handleActionFunctionCompletion = function() {
console.log('Step 4: AJAX call complete. Re-rendering apex:dataTable component.');
DF12Examples.endTime = Date.now();
if (console) {
console.log(
'elapsed time: ' +
(DF12Examples.endTime - DF12Examples.startTime) +
'ms'
);
}
};
</script>
</apex:define>
</apex:composition>
</apex:page>