Calling apex function

  • 6
  • Question
  • Updated 3 months ago
  • Answered
Is there any way to write code to call an apex function from within skuid?
Photo of Ant Belsham

Ant Belsham

  • 1,022 Points 1k badge 2x thumb

Posted 5 years ago

  • 6
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Ant, there are 4 main ways to call Apex functions from within Skuid:

1. Use the AJAX toolkit's "sforce.apex.execute()" method to execute an Apex Web Service (requires you putting your Apex logic into a Web Service)

2. Use the Salesforce Apex REST technology to expose your methods as an Apex REST Service, and then callout to this using jQuery get() or similar calls.

3. Have your Apex logic initiated by Triggers --- so that when you make data changes from within Skuid, such as changing the Status of a record, back-end Apex is kicked-off.

4. (probably what you want to do) Rather than initiating Skuid from Redirects, have your Visualforce Override pages actually include Skuid Pages through the
<skuid:page [page=pageName] [actionType=actionType objectType=objectType]>
Visualforce Component. That way, you can have a custom Apex controller / controller extension for your Visualforce Page, which contains your Apex functions, BUT you can still have your Skuid Page. We recommend making your Apex logic into JavaScript Remoting methods, so that it's easy to execute them from JavaScript. Using actionFunctions to kick off Apex logic may be problematic.

Example Visualforce Page:



<apex:page docType="html-5.0" readOnly="true"
standardController="Account" extensions="MyApexClass">

<skuid:page page="MySkuidPage"/>

</apex:page>


Example Apex Class:



public with sharing class MyApexClass {

@RemoteAction
public static Account createAccount(String accountName) {
Account a = new Account(Name = accountName);
return a;
}

}


Example use from within Skuid JavaScript code (e.g. a Snippet):



var newAccount = MyApexClass.createAccount('Acme Generators');
alert('New Account Id: ' + newAccount.Id);
Photo of Salesforce Dev007

Salesforce Dev007

  • 308 Points 250 badge 2x thumb
Could we access the webservice objects within javascript too? for example this:

global class TestInvocable
{
   global class DispatchInfo 
   {
      webservice Date dispatchDate;
      webservice String shippingCompany;
   }
    webservice static String testInvocableMethod(DispatchInfo dispatch)
    {
        System.debug('Dispatch info');
        System.debug('date: ' + dispatch.dispatchDate);
        System.debug('shipping company: ' + dispatch.shippingCompany);
        
        return 'Ok';
    }
}
I need to access the 'DispatchInfo' object within my code snippet. I tried doing something like this:

var dipatchInfo = sforce.Xml('DispatchInfo');

but this doesnt work as dipatchInfo was always undefined. Any help on this would be appreciated. Thanks.
(Edited)
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
I'm not sure, would have to research, but an easier way would be to make your Apex method take a String argument, which is actually JSON, and then serialize client-side to JSON and deserialize server-side into a DispatchInfo object, e.g.

global class TestInvocable
{
   private class DispatchInfo 
   {
      Date dispatchDate;
      String shippingCompany;
   }
    webservice static String testInvocableMethod(String dispatchJSON)
    {
        DispatchInfo dispatch = (DispatchInfo) JSON.deserialize(dispatchJSON,DispatchInfo.class);
        System.debug('date: ' + dispatch.dispatchDate);
        System.debug('shipping company: ' + dispatch.shippingCompany);
        
        return 'Ok';
    }
}

And then in JavaScript you could do this (if you're using the AJAX Apex Toolkit):

var dispatch = {
    dispatchDate: new Date(),
    shippingCompany: "Acme"
};
var result = sforce.apex.execute("TestInvocable","testInvocableMethod",{ dispatchJSON: JSON.stringify(dispatch) });
console.log('the result was: ' + result);
Photo of Salesforce Dev007

Salesforce Dev007

  • 308 Points 250 badge 2x thumb
This is what I needed...thanks.
Photo of ktyler

ktyler

  • 9,244 Points 5k badge 2x thumb
I have written some code I need to run before I call the skuid page... it creates a running balance entry on a series of charges for an account. Can I use this last method in a way that makes sure the running balance code runs before the skuid page loads ?
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Here is an example of how to do strategy 1: using the AJAX Toolkit to execute Apex code defined as a Web Service.

1. Ensure that you have your Apex code defined as a Web Service

Here is a dummy Apex class that exposes two Web Service methods, "Prequalify" and "SubmitForProcessing":



2. In your Skuid Page, add the Apex from AJAX toolkit as a new "External" JavaScript Resource:

(a) Go to your page's Resources tab
(b) Click on "JavaScript". Click the green plus icon that appears to the right to add a new JavaScript Resource.
(c) Click on your newly-created JavaScript Resource. Change its type to "External". (d) For Resource URL, put /soap/ajax/29.0/apex.js



This is VERY important, and must be done on all Skuid Pages from which you wish to leverage the "Apex via AJAX Toolkit" approach.

Skuid automatically always loads in the base AJAX Toolkit JavaScript (/soap/ajax/[latest_version]/connection.js), so all you need to do is load in the Apex library.

3. In your Skuid Page, add a new JavaScript Resource of type "Inline (Snippet)" which will contain your button-calling logic:

We are going to add a new Snippet called "Prequalify", which will call our Prequalify web service in our OpportunityUtils class, passing in a parameter "opportunityId", which will contain the Id of the Opportunity record we are interested in:





4. Add a new button to your Page Title, of type "Custom: Run Skuid Snippet", which is set to call the "Prequalify" Snippet:



Result: a button which runs your Apex web service on the selected Opportunity, and returns the result.



Photo of Sriram

Sriram

  • 70 Points
Hi Zach, I want to pass list of Ids from skuid to salesforce webservices static method.
Is this possible, if yes please give me suggession.

I want to convert array to list and need to send that list of ids as a parameters.

Thanks,
Sreeram
Photo of Charlie Jonas

Charlie Jonas

  • 670 Points 500 badge 2x thumb
Zach,

I gave this a try but unfortunately, I'm getting an error message:

faultcode:'soapenv:Client', faultstring:'No operation available for request {http://soap.sforce.com/schemas/package/MyClass}myMethod, please check the WSDL for the service.' 
Any idea what might be going on?  I set it up exactly as you described.
Photo of Moshe Karmel

Moshe Karmel, Champion

  • 8,646 Points 5k badge 2x thumb
According to this post: https://developer.salesforce.com/forums/ForumsMain?id=906F00000008wk5IAA you might have forgotten to use the "Webservice" keyword on your apex method.
Photo of Charlie Jonas

Charlie Jonas

  • 670 Points 500 badge 2x thumb
Moshe, no I didn't.

It actually turns out that the apex toolkit for whatever reason converts the case on the webservice method.  I changed the method name from myMethod to MyMethod and it work.  Weird
Photo of Rob Hatch

Rob Hatch, Official Rep

  • 44,006 Points 20k badge 2x thumb
Bottom line.. I'm glad it worked for you.
Photo of ravi teja

ravi teja

  • 238 Points 100 badge 2x thumb
hii guys i tried to do that opportunity example i paste the code in snippet and in a button i select snippet name but its not working for me means that on click event nothing happens what wrong did i do can anyone tell me
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Two questions: 
  1. Does the new action framework action "Run Custom Apex Action" change any of this?
  2. If we pursue option 2 and expose APEX methods as a REST service, can we then build a skuid REST API model against that service?
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
bump.
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
1. If you expose your apex logic as Apex Invocable Methods, then you can call the logic through the "Run Custom Apex Action". This approach is good if the Apex logic has a general purpose, such as "Send SMS via Twilio", and thus should be available to call from any Skuid Page. You can lock down access to Invocable Apex Classes via Profile / Permission Sets, but not by execution context (e.g. VF Page), so If you need to lock down access to this Apex to be from a particular execution context, then the Remote Action approach would be better.
2. REST Models are a great alternative, yes! The nice thing about this approach is that you can then use regular Skuid Model API methods to, in effect, influence Apex code. Highly recommended.
Photo of Jack Sanford

Jack Sanford, Champion

  • 8,322 Points 5k badge 2x thumb
Are there any tutorials for building a REST model to access a webservice in apex?
Photo of Arne-Per Heurberg

Arne-Per Heurberg

  • 1,336 Points 1k badge 2x thumb
Is there documentation on using classes exposed with REST with Skuid? I must not be setting authorization correctly.
Photo of Arne-Per Heurberg

Arne-Per Heurberg

  • 1,336 Points 1k badge 2x thumb
still haven't been able to get REST to work
Photo of Gautam Kasukhela

Gautam Kasukhela

  • 100 Points 100 badge 2x thumb
Hey Zach,
    I used the 4th option that you suggested. Embedded the Skuid Page in my visualforce page. I used the following script in my JavaScript Snippet
alert('hi');
var newAccount = TestAccountEntrySkuid.createAccount();
alert('New Account Id: ' + newAccount.Id);

When I click on the button for which I have configured the above Java Script Snippet, it only shows the first alert and post that nothing happens.
Am I missing anything here???
My Controller contains a blank constructor and a method to insert an account record. Method annotation is @RemoteAction .
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Are there any errors in the JavaScript Console when you run this?
Photo of KVin

KVin

  • 1,158 Points 1k badge 2x thumb
Hey Gautam,

I ran into same issue few days ago, on console you should have an error, saying that remoting error for VF remoting - missing parameters or something similar.

Try to use the function call like below and see. (it always expects callback function, so i modified like below and works for me)


TestAccountEntrySkuid.createAccount(function(result){

alert('New Account Id: ' + result.Id);
});
Photo of Gautam Kasukhela

Gautam Kasukhela

  • 100 Points 100 badge 2x thumb
Hey Kvin, 
   Following is the error in the console that I am getting:-
 Uncaught ReferenceError: TestAccountEntrySkuid is not defined ,
Photo of Gautam Kasukhela

Gautam Kasukhela

  • 100 Points 100 badge 2x thumb
Hello Zach, 
       Uncaught ReferenceError: TestAccountEntrySkuid is not defined . This is the exception that I encounter in the console. Is there anything that I need to do specifically? The method is static, so I assumed that 'TestAccountEntrySkuid.createAccount();' should take care of calling the method directly.

Regards,
Gautam.
Photo of KVin

KVin

  • 1,158 Points 1k badge 2x thumb
Hey Gautam,

I believe you are trying to preview the Skuid page alone and trying to use your class to work as extension.

Did you add this class as an extension to your VF page as Zach explained in above initial posts ?


<apex:page docType="html-5.0" readOnly="true" standardController="Account" extensions="TestAccountEntrySkuid">

   <skuid:page page="MySkuidPage"/>
</apex:page>

Try to preview this VF page once created, that should resolve the issue.
Photo of Jayesh Bhatnagar

Jayesh Bhatnagar

  • 476 Points 250 badge 2x thumb
We have been successfully using option 1 mentioned by Zach at the top of this post i.e the AJAX toolkit's sforce.apex.execute method. But we are receiving errors when we try to expose the same skuid page in the salesforce community. I see an error in the console that indicates it may be an error related to the External resource /soap/ajax/29.0/apex.js that is added to the skuid page. Here is the console error:
apex.js:48 Uncaught TypeError: Cannot read property 'push' of undefined
    at sforce.Apex.execute (https://stagefull-afl.cs52.force.com/soap/ajax/37.0/apex.js:48:61)
    at https://stagefull-afl.cs52.force.com/Customer/resource/1504866722000/AFLInquiryOrderResourceWorkflow...
    at Object.callback (eval at <anonymous> (https://stagefull-afl.cs52.force.com/Customer/resource/1495240238000/skuid__JQueryJS:2:13735), <anonymous>:150:64)
    at Object.K.aa.when.all.then.c (https://stagefull-afl.cs52.force.com/Customer/resource/1496757765000/skuid__SkuidJS:8:17252)
    at Object.<anonymous> (https://stagefull-afl.cs52.force.com/Customer/resource/1495240238000/skuid__JQueryJS:3:7502)
    at j (https://stagefull-afl.cs52.force.com/Customer/resource/1495240238000/skuid__JQueryJS:3:6134)
    at Object.fireWith [as resolveWith] (https://stagefull-afl.cs52.force.com/Customer/resource/1495240238000/skuid__JQueryJS:3:6946)
    at Object.e.(anonymous function) [as resolve] (https://stagefull-afl.cs52.force.com/Customer/resource/1495240238000/skuid__JQueryJS:3:7926)
    at Object.<anonymous> (https://stagefull-afl.cs52.force.com/Customer/resource/1496757765000/skuid__SkuidJS:2:6047)
    at Object.<anonymous> (https://stagefull-afl.cs52.force.com/Customer/resource/1495240238000/skuid__JQueryJS:3:7502)
sforce.Apex.execute @ apex.js:48

Any ideas?
Photo of Jayesh Bhatnagar

Jayesh Bhatnagar

  • 476 Points 250 badge 2x thumb
Just to let everyone know calling apex from skuid in a salesforce community using sforce.apex.execute is not an issue. The above issue was caused by an undefined variable being passed to the apex class. The error message returned was very ambiguous. Hopefully this will save somebody a lot of frustration.