23

Is it possible to call javascript remoting in a static resource?

I'm creating an AngularJS application, and to stick with best practices I would like to put my services in separate files. Theses services are used by angular controllers to get data out of Salesforce.

It works as expected when I define the service in the visual force page as follows:

<script>
      salesCentral.factory('contentData', ['$q', '$rootScope', function($q, $rootScope) {

        return function() {
            var deferred = $q.defer();

            Visualforce.remoting.Manager.invokeAction(
                '{!$RemoteAction.MyJSRemoteController.getContentList}',
                function(result, event) {
                    $rootScope.$apply(function() {
                      if (event.status) {
                        deferred.resolve(result);
                      } else {
                        deferred.reject(event);
                      }
                    })
                },
                { buffer: true, escape: true, timeout: 30000 }
            );

            return deferred.promise;
        }

    }]);
</script>

However, when I include the exact same code from a static resource I get this error

TypeError: Cannot read property 'MyJSRemoteController' of undefined at Object.$VFRM.Util.getObject (https://cs2.salesforce.com/jslibrary/1383321200000/sfdc/VFRemote.js:119:364) ...

Does javascript remoting have to be defined directly inside the VisualForce Page?

23

Javascript remoting can be used within a static resource.

This method fails in a static resource because of the use of the merge field '{!$RemoteAction.MyJSRemoteController.getContentList}' and not because of the use of javascript remoting.

Using the alternate javascript remoting syntax below will work because it is not dependent on a merge field:

MyJSRemoteController.getContentList(function(result, event) {
    //callback stuff
});

Although less elegant, you can also use the following syntax, which is closer to the documented syntax for JS Remoting.:

<script>
      salesCentral.factory('contentData', ['$q', '$rootScope', function($q, $rootScope) {

        return function() {
            var deferred = $q.defer();

            Visualforce.remoting.Manager.invokeAction(
                'MyJSRemoteController.getContentList',
                function(result, event) {
                    $rootScope.$apply(function() {
                      if (event.status) {
                        deferred.resolve(result);
                      } else {
                        deferred.reject(event);
                      }
                    })
                },
                { buffer: true, escape: true, timeout: 30000 }
            );

            return deferred.promise;
        }

    }]);
</script>
  • Thanks, trying thing now! merge field? Any additional documentation – NSjonas Nov 13 '13 at 13:42
  • Awesome, Worked like a charm – NSjonas Nov 13 '13 at 21:40
10

To add to Phil's answer, you can use Javascript remoting in a static resource. However, the only tricky issue is namespacing.

There are very few good examples of the alternate javascript remoting syntax available. And none of the dealt with namespacing. So this is how you do it. You will need to pass in the namespace to your static js file. We do this in the onclick function that kicks off the remoting.

<input id="input" onclick="javascriptRemoteFunction(window['{!Namespace}']);" type="button">

To actually get the namespace you will need this function in your apex controller:

public String getNamespace(){
        ApexClass getNamespaceClass = [
            select NamespacePrefix
            from ApexClass
            where Name = 'NameOfClass'
        ];
        return getNamespaceClass.NameSpacePrefix;
    }
}

And finally your static javascript file, that uses the alternate syntax will look like this:

function javascriptRemoteFunction(namespaceObject) {
        var searchDropdownCategory = document.getElementById('sharing_search').value;
        var searchBoxValue = document.getElementById('searchValue_sharing_search').value;

        namespaceObject.AjaxUserRoleSearch.ajaxGetRoles(
            searchBoxValue, searchDropdownCategory,
            function(result, event){
                if (event.status) {
                    doStuff(); 
                }
            }
        );
    }
2

To augment Phil's answer, we can pass variables like this:

var myObj = {

    // add properties    

};

MyJSRemoteController.getContentList(myObj, function(result, event) {

    //callback stuff

});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.