The Silver Lining

Lessons & Learnings from a salesforce certified technical architect.

Salesforce JavaScript Remoting: Using Apex and JavaScript objects to pass data from client- to server-side and vice versa

with 13 comments

I’ve spoken about how to do this at a high-level during Cloudstock London and there are hints at how it can be done but no formal documentation that I’ve found, so here we are :)

Quite simply JavaScript Remoting will transform Apex objects and classes (or collections of these types) into JavaScript objects for you. The opposite is true too but there are some rules you need to observe.

Apex Types to JavaScript Equivalents

This is the easier of the type conversions in that you don’t have to really do anything to make it happen. The code below uses a custom class that I’ve defined but you can do the same with any sObject too. Let’s have a look at the code.

The Controller

public with sharing class RemotingObjectsController {

    /* The remoting method simply instantiates a two custom types, puts
       them into a list and then returns them. */
    @RemoteAction
    public static List<CustomClass> getClassInstances(){
        List<CustomClass> classes = new List<CustomClass>();

        CustomClass me = new CustomClass('Wes');
        CustomClass you = new CustomClass('Champ');

        classes.add(me);
        classes.add(you);

        return classes;
    }

    /* My custom type */
    public class CustomClass{
        public String firstName{get;set;}

        CustomClass(String firstName){
            this.firstName = firstName;
        }
    }
}

The Visualforce

<apex:page controller="RemotingObjectsController">
  <script>
      // Will hold our converted Apex data structures
      var classInstances;

      Visualforce.remoting.Manager.invokeAction(
        '{!$RemoteAction.RemotingObjectsController.getClassInstances}',
        function(result, event) {
          // Put the results into a var for pedantries sake
          classInstances = result;

          console.log(classInstances);

          // Assign the first element of the array to a local var
          var me = classInstances[0];

          // And now we can use the var in the "normal" JS way
          var myName = me.firstName;
          console.log(myName);
        });
  </script>
</apex:page>

The Output

Console output from the JS code.

JavaScript Types to Apex Equivalents

This is a little tricker, especially when it comes to sObjects. Note that the approach below works for classes and sObjects too.

The Visualforce Page

<apex:page controller="RemotingObjectsController">
  <script>
      /* Define a JavaScript Object that looks like an Account */
      /* If you were using custom objects the name must include the "__c" */
      function Account(){
          /* Note the field names are case-sensitive! */
          this.Id = null; /* set a value here if you need to update or delete */
          this.Name = null;
          this.Active__c = null; /* the field names must match the API names */
      }

      var acc1 = new Account();
      acc1.Name = 'Tquila';
      acc1.Active__c = 'Yes';

      var acc2 = new Account();
      acc2.Name = 'Apple';
      acc2.Active__c = 'Yes';

      var accounts = new Array(acc1, acc2);

      Visualforce.remoting.Manager.invokeAction(
        '{!$RemoteAction.RemotingObjectsController.insertAccounts}',
        accounts,
        function(result, event) {
          console.log(result);
        });
  </script>
</apex:page>

The Controller

There not much to the controller in this case.

public with sharing class RemotingObjectsController {

    @RemoteAction
    public static void insertAccounts(List<Account> accounts){
        insert accounts;
    }

}

Why is this cool?

Good question. If the Force.com Platform didn’t do this for you then we – the developer – would need to convert ours types explicitly on both the server-side and the client-side, and man-oh-man is that boring, error-prone work. Yet again the guys at salesforce.com have built in a convenience that saves us time and let’s us get on with the work of building cool apps.

About these ads

Written by Wes

June 22, 2012 at 11:06 am

13 Responses

Subscribe to comments with RSS.

  1. Interesting post! I did not know Salesforce can do automatic type conversion. It’s also worth pointing out the awesome ‘apex:type’ key(sorta annotation) that you can use if your remote method parameter is an interface. More details in the docs here: http://www.salesforce.com/us/developer/docs/pages/Content/pages_js_remoting.htm

    Cheers,
    Anup

    anupj

    June 25, 2012 at 10:07 am

  2. SutoCom

    July 25, 2012 at 6:40 pm

  3. Hi nice post,
    I have a question –

    You talked about the object which are already defined in salesforce. I want to send a map to the remote method. Is there any trick. I am also trying with jquery serialize array to send the json data to the remote method but dont know its not working.

    This will help you to understand what I want

    https://sites.secure.force.com/success/servlet/rtaImage?eid=a1X30000000dkOn&feoid=00N30000006WEw0&refid=0EM300000016hdr

    Thanks in advance.

    Lokesh Gupta

    July 31, 2012 at 8:28 am

  4. I understand this is probably basic knowledge for most devs but I fought with this example for hours after realizing you forgot to add a comma in the most important part of the jQuery code.
    Visualforce.remoting.Manager.invokeAction(
    ‘{!$RemoteAction.RemotingObjectsController.insertAccounts}’,
    accounts, <———————-missing comma
    function(result, event) {
    console.log(result);
    });

    I definitely was able to use this to my benefit though so no worries :)

    Just please add the comma

    Ben

    August 17, 2012 at 5:01 pm

    • Whoops! Thanks for letting me know :)

      Wes

      August 19, 2012 at 1:29 pm

  5. Hi!
    There is a far more readable notation for this call:

    RemotingObjectsController.insertAccounts(accounts,function(result, event) {
    console.log(result);
    });

    Cheers,
    Detlef

    Detlef

    August 23, 2012 at 3:07 pm

    • Very true, that does work very well but it won’t work in managed packages unless you hardcode the prefix.

      Wes

      September 3, 2012 at 3:52 pm

  6. [...] Salesforce JavaScript Remoting: Using Apex and JavaScript Objects to pass Data from client-to server… jQuery(document).ready(function($) { [...]

  7. The platform does a great job of converting data to the Javascript equivalent in most cases… I’ve found that Date objects are a tricky exception. If you have a remoted method with SObjects as a parameter (or contained in a parameter, such as List), field values of type “date” are serialized as the integer milliseconds-since-epoch UTC value for midnight on that date, and appear to you as strings. Constructing a local Date from this naively can result in dates that are one day off. The following is my fix, interposed wherever in your (Javascript) code it makes sense:

    var datefield = new Date(parseInt(datefield_from_server)); // string returned in remoted method response
    datefield = new Date(datefield.getUTCFullYear(), datefield.getUTCMonth(), datefield.getUTCDate());

    Javascript experts probably have a better way, but it works for me…

    Jeff Trull (@JaafarTrull)

    October 5, 2012 at 11:09 pm

  8. I’m still having a hard time seeing the advantage of remoting over the AJAX toolkit. Have you tried both or can you offer some input?

    Phil

    April 10, 2013 at 8:11 pm

    • Sure. The AJAX toolkit is a wrapper on the webservices API and is based on the partner WSDL. Remoting let’s you call (specially annotated) Apex Controller methods from JavaScript in your Visualforce.

      Wes

      April 10, 2013 at 9:06 pm

      • Thanks for the explanation. I guess what I’m getting at is in the example provided you’re just doing a DML operation which you could do just as easily with the AJAX toolkit without a controller action. Maybe I just need to dig up a more complex example to see the additional benefits.

        Phil

        April 10, 2013 at 9:11 pm

  9. Hi Wes,
    I was wondering if you had ever seen this error before: Uncaught TypeError: Cannot read property ‘CLASS_NAME’ of undefined, VFRemote.js line 122. My javascript remoting is throwing this error.

    Here’s what I’m confused about. This code works:
    RemoteClassController.remoteMethod(param1,param2,param3,handleUpdatesCheck);
    but this code doesn’t:
    Visualforce.remoting.Manager.invokeAction(‘{!$RemoteAction.RemoteClassController.remoteMethod}’,param1,param2,param3,handleUpdatesCheck);

    where handleUpdatesCheck is another function that handles the results. Do you have any idea why the first option works but the second doesn’t? I’d like your input because we’re using a managed package and I’d really like to avoid having to hack together a solution for managed/unmanaged if possible and I know the second option works both inside and outside of the package. Until then, I will use your workaround here: http://th3silverlining.com/2012/02/26/salesforce-javascript-remoting-and-managed-packages/

    Thanks again!
    –Liz

    Liz

    May 17, 2013 at 9:45 pm


Leave a Reply

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

WordPress.com Logo

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

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 2,204 other followers

%d bloggers like this: