6

I am new to salesforce and Apex programming. We call remoteactions from javascript in 2 ways.

1.By using namespace.controller.method
2.By using Visualforce.remoting.Manager.invokeAction pattern.

I am a little surprised as I didn't expect these namespaces to be accessible in javascript without including any scripts and without the help of any apex tags. Also I tried an example with Ajax toolkit. I had to include the connection.js file which would provide access to sforce.connection methods. so I was expecting the remoteactions to work the same way. Can someone help me to how the namespace in method1 and the Visualforce namespace in method2 are accessible from javascript?

2
  • Because visualforce wires up all the things you need to do it automatically. If you are doing it in a JS button you need to specify what libraries to include.
    – Eric
    Commented Feb 24, 2017 at 5:44
  • Is Ajax toolkit something used very rarely? could there be a reason behind why that library is not wired up automatically?
    – Saranya
    Commented Feb 24, 2017 at 5:57

3 Answers 3

6

The AJAX Toolkit is a generic toolkit that is designed to be used anywhere: in a JavaScript button, on your own website, in a Chrome/Firefox/IE browser extension, desktop apps, NodeJS apps, etc. It's a generic JavaScript framework that uses SOAP-based API calls to interact with salesforce.com. The reason why you have to include the AJAX toolkit is because it's a generic library that isn't tied to Visualforce. The AJAX Toolkit is a SOAP-based client, and consumes API calls (look up the rate limiting docs online).

Remoting, in contrast, is built specifically for Visualforce. You can't call these methods anywhere you like, but while you're in a Visualforce page, the platform automatically includes the necessary scripts to allow you to call these methods. Remoting does not use API calls, but does count towards the bandwidth limits for public pages when used on Sites.com. Remoting can only access methods that are included in the controller or extensions that are imported into the page, and also restricts public methods when used in an iframe.

You should prefer to use Remoting when possible, and the AJAX Toolkit when you can't.

0
7

This question is really interesting, which also force me to think, what's there exactly, and how it works, here is the background:

let's understand this process with an example, I created a Class with single Remote action method and a page which using that method, see code:

Apex Controller:

public class ApexController {   

   @RemoteAction
   public static string RemoteMethod1(){
       return 'Successfull';
   }    
}

VF Page:

<apex:page controller="ApexController" showHeader="false" standardStylesheets="false">

<a href="javascript:callJSRemoting()">Click</a>

<script>
function callJSRemoting(){
    ApexController.RemoteMethod1(
        function(result, event) {
            if (event.status) {
                alert(result);
            }
            else if(event.type === 'exception'){
                console.log('Exception: '+event.message);
            }
            else{
                 console.log('Error: '+event.message);
            }
        },
        {buffer: false}    
    );
}

</script>
</apex:page>

Now let's start pilling the layers, if you go to the page and inspect element, you will see something like that:

<script src="/jslibrary/1485897292000/sfdc/VFRemote.js" type="text/javascript"></script>
<script type="text/javascript">
Visualforce.remoting.Manager.add(new $VFRM.RemotingProviderImpl({"vf":{"vid":"06641000006mTfb","xhr":false,"dev":false,"tst":false,"dbg":false,"tm":1487916828815,"ovrprm":false},"actions":{"ApexController":{"ms":[{"name":"RemoteMethod1","len":0,"ns":"","ver":39.0,"csrf":"VmpFPSxNakF4Tnkwd01pMHlOMVF3TmpveE16bzBPQzQ0TVRaYSxRQ0pMQWNqQ2syOGlrZ1lDX2dQVzNyLFlXUTRaV1Jo"}],"prm":1}},"service":"apexremote"}));
</script>

If you want to understand it, VF Compiler adding a VF remoting JS file as reference and it went to the controller class which is added to the page and read all the @Remoteaction Methods and create a object which is embedded there, check it:

actions":{"ApexController":{"ms":[{"name":"RemoteMethod1","len":0,"ns":"","ver":39.0,"csrf":"VmpFPSxNakF4Tnkwd01pMHlOMVF3TmpveE16bzBPQzQ0TVRaYSxRQ0pMQWNqQ2syOGlrZ1lDX2dQVzNyLFlXUTRaV1Jo"}],"prm":1}}

So that object contains the reference of your class and the @Remoteaction Methods, Now when you call any Vf remoting function with the controller.RemoteMethod, it directly search that reference from VF js library and execute the function.

if you further drill the particular Remoteaction method, then you will see of the option or attributes there like:

{"name":"RemoteMethod1","len":0,"ns":"","ver":39.0,"csrf":"VmpFPSxNakF4Tnkwd01pMHlOMVF3TmpveE9Eb3pOUzR3TnpkYSxJWnR4UDdoXzZIR0tDSkFHMmwtMVQzLFlXUTRaV1Jo"}

As you can see above it contains all the required parameters to call the VF Remoting call, it contains name of the Method, version, parameter length (if method contains any) and CSRF token to make a POST ajax call internally.

Now's let add an another Remoteaction method into class :

Modified Class with two @Remoteaction methods

public class ApexController {

@RemoteAction
public static string RemoteMethod1(){
    return 'Successfull';
}

@RemoteAction
public static string RemoteMethod2(string name, string age){
    return 'Successfull Method 2';
}
}

Now if we see on page we will see below Remote call object reference:

Visualforce.remoting.Manager.add(new $VFRM.RemotingProviderImpl({"vf":{"vid":"06641000006mTfb","xhr":false,"dev":false,"tst":false,"dbg":false,"tm":1487917631851,"ovrprm":false},"actions":{"ApexController":{"ms":[{"name":"RemoteMethod1","len":0,"ns":"","ver":39.0,"csrf":"VmpFPSxNakF4Tnkwd01pMHlOMVF3TmpveU56b3hNUzQ0TlRGYSxrVXkzTTdUOGEtN1hMaldNWUVQVlNmLFlXUTRaV1Jo"},{"name":"RemoteMethod2","len":2,"ns":"","ver":39.0,"csrf":"VmpFPSxNakF4Tnkwd01pMHlOMVF3TmpveU56b3hNUzQ0TlRGYSx3SGljN19qVUZVdVJIZEc0ejJjSzNKLE5XTmxZV1kx"}],"prm":1}},"service":"apexremote"}));

if you check it, it contains two methods with all the details about the @remoteaction method, as per the new Method it contains parameters/argument also that's why length(len) attribute comes as 2, see below:

{"name":"RemoteMethod2","len":2,"ns":"","ver":39.0,"csrf":"VmpFPSxNakF4Tnkwd01pMHlOMVF3TmpveU56b3hNUzQ0TlRGYSx3SGljN19qVUZVdVJIZEc0ejJjSzNKLE5XTmxZV1kx"}

If our controller doesn't have any @Remoteaction method then on page side the compiler will not add any VF reference library or remoting method object.

So in conclusion here the Process:

  • VF Compiler compile the page with Class and get all the @remoteaction methods, if @remoteaction method exist then it will add a VF JS library and all Methods reference as Object in page

  • In page when you reference/call any remoting method you by using VF pattern namespace.controllerclass,methodname, it will search for the VF reference object and it will bound that particular object reference with the function.

  • Now the bounded function with all remoting method reference calls the internal ajax call from VF JS library and execute ajax call to controller which get the result and that result pass to the callback function.

I hope it will clear some of doubts.

3
  • This is really a valuable information, Thanks a ton!!
    – Saranya
    Commented Feb 24, 2017 at 6:53
  • If I have remote action in the js file and I want to load that at run time. so is there any way to register the apex controller at run-time, because it throws an error Unable to invoke action 'CustomerOrderCtrl.getCustomer': no controller and/or function found Commented Mar 31, 2017 at 8:08
  • Can you share your code, which you are using in your JS file for defining VF remoting? Commented Apr 1, 2017 at 10:17
0

You can use the $RemoteAction global in javascript to access the correct namespace, if any, for your remote action.

<script type="text/javascript">
function getRemoteAccount() {
    var accountName = document.getElementById('acctSearch').value;

    Visualforce.remoting.Manager.invokeAction(
        '{!$RemoteAction.MyController.getAccount}', 
        accountName, 
        function(result, event){
            if (event.status) {
                document.getElementById('acctId').innerHTML = result.Id
                document.getElementById('acctName').innerHTML = result.Name;
            } else if (event.type === 'exception') {
                document.getElementById("responseErrors").innerHTML = event.message;
            } else {
                document.getElementById("responseErrors").innerHTML = event.message;
            }
        }, 
        {escape: true}
    );
}
</script> 

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .