Update: I’ve recently recieved a very informative email from Salesforce. In this email, Salesforce explained some of the ideas that went into their design. It made a ton of sense, and I’ll talk about it at the end of this post. And thanks for the info Salesforce!
I recently got Javascript Remoting enabled in my developer org and it’s certainly a good feature to have in your bag of tricks. If you’ve used Visualforce and included a lot of Javascript bell’s and whistle’s, then you undoubtedly came across some situation where you wanted to have the javascript portion of the code kick off something in the Controller.
Traditionally this was done through actionFunctions. One thing I always hated about actionFunctions was what you needed to do to support parameters to these functions. You had to set up parameters in the action function which were bound to some assignable property of the controller. This made the code somewhat harder to read, and you were forced to pollute the controller level namespace with these variables whether or not they belonged there. Javascript remoting does help address this, somewhat, but it does impose some restrictions which may not fit within your code framework.
The following code are two different implementations of the same code. One using an actionFunction and some controller level properties to pass parameter data, and the second is using Javascript remoting. We’ll have javascript pass to the controller a name to search.
actionFunction Version
public with sharing class VFComparisonController {
public List<account> listOfAccounts{get;set;}
public String name {get;set;}
public PageReference getAccountsByName(){
listOfAccounts=[select id, name from Account where Name = :name];
return null;
}
}
<apex:page controller="VFComparisonController" >
<script type="text/javascript" src="{!$Resource.js_jQueryLib}"/>
<apex:form >
<apex:actionfunction name="getAccountsByName" action="{!getAccountsByName}" rerender="resultArea">
<apex:param name="name" value="" assignTo="{!name}"/>
</apex:actionfunction>
<script type="text/javascript">
j$=jQuery.noConflict();
j$(document).ready(function(){
getAccountsByName("IBM");
});
</script>
<apex:outputPanel id="resultArea" >
<apex:repeat var="a" value="{!listOfAccounts}" >
<apex:outputLabel value="{!a.id}, {!a.name}" /> <br/>
</apex:repeat>
</apex:outputPanel>
</apex:form>
</apex:page>
Javascript Remoting Version
global with sharing class JSRemotingController {
@RemoteAction
global static List<account> getAccountsByName(String name){
List<account> account = [select id, Name from Account where name = :name];
return account;
}
}
<apex:page controller="JSRemotingController">
<script type="text/javascript" src="{!$Resource.js_jQueryLib}"/>
<script type="text/javascript">
j$=jQuery.noConflict();
JSRemotingController.getAccountsByName("IBM", function(result, event){
if (event.status &amp;amp;amp;&amp;amp;amp; result){
j$.each(result, function(){
j$("#targetId").append(this.Id+", "+this.Name+"<br/>");
})
}
}, {escape:true});
</script>
<div id="targetId"></div>
</apex:page>
So, first comparing the two classes, the Javascript Remoting version is much more cleaner. The Javascript Remoting version has the name variable and the List<Account> return as a part of its method signature as opposed to having to be decalred at the class level. It’s much easier to understand that name and List<Account> are limited to the scope of the method.
However, note that the Javascript remoting method must be declared both global and static. Static is a bit of a bummer, as it means you won’t have access to any class instance variables. In contrast, the actionFunction version directly modified the state of the Controller instance, and the invoked method has access to all instance variables.
Update: So, why did Salesforce do this? well, if you’ve ever created a complex Visualforce page, one of the things you probably ran into is the “viewstate” (for more info on the viewstate, look here.). If you’ve heard about the viewstate, then you probably know that in general, the larger your viewstate, the slower your performance when it comes to acting on commandButtons, commandLinks, and actionFunctions. So to keep the Javascript Remoting call light and VERY quick, the viewstate is not transmitted.
From this perspective, it makes sense that the Javascript Remoting call is connected to a static function, as static functions are typically considered stateless. Since the viewstate is not transmitted, I doubt that the Javscript Remoting function would be even able to access controller static variables, but that’s just a guess for now and I’ll come back and update this when I get to trying it out for myself. But, even if this is a limitation, you could try to pass any variables you need in on the Javscript Remoting call. One note on this approach though, you will need to express your state in primitive data types, as you can only pass in primitive data types (You can return primitives, sObjects, or arrays of either of those types).
So when deciding which method to use, you’ll have to consider a few things: 1) Performance, 2) What state you’ll need to push to make the call you want, and one more point which we should mention, 3) How you will modify your Visualforce view? When using actionFunctions, you have a rerender tag you can use and it’s so simple to use in conjunction with other VF components. When using Javascript Remoting, just remember that you’ll have to roll your own here, but if you’re using something like jQuery, this may not be much code at all.
Add a Comment »