As with the Visualforce Apex controller action methods you've seen in the earlier chapters, the Service layer is also designed to be called from Visualforce JavaScript Remoting methods, as follows:
public with sharing class RaceResultsController { @RemoteAction public static List<RaceService.ProvisionalResult>loadProvisionalResults(Id raceId) { return RaceService.calculateProvisionResults( new Set<Id>{ raceId }).get(raceId); } }
To make Lightning Component controller server-side calls to Apex use the @AuraEnabled
annotation method:
public with sharing class RaceResultsController { @AuraEnabled public static List<RaceService.ProvisionalResult>loadProvisionalResults(Id raceId) { return RaceService.calculateProvisionResults( new Set<Id>{ raceId }).get(raceId); }
You will also need to apply the @AuraEnabled
method to accessors for Apex types referenced by the Controller methods:
public class ProvisionalResult { @AuraEnabled public Integer racePosition {get; set;} @AuraEnabled public Id contestantId {get; set;} @AuraEnabled public String contestantName {get; set;} }
In both these cases, however, there is no try
/catch
block, as error handling is done by the client code to render the messages. When exceptions are thrown, the platform takes care of catching the exception and passing it back to the calling JavaScript code for it to display accordingly. In short, there is no need to invent your own error message handling system; just let the platform handle pass it back to the client JavaScript code for you. Remember though that you still need to handle the error message in your client side JavaScript logic; this will not be done by Visualforce for you.
With the addition of more complex logic in the client via JavaScript, more attention needs to be given to Separation of Concerns. The following points provide some guidelines for this:
The workarounds are to either not use enum's and drop back to using string data types or create Apex class data types within the controller class and perform your own marshaling between these types and service types (leveraging the Enum.name()
method to map Enum's to string values). The choice is between your desire to protect your Service layer's use of Enum's (especially if it is your public-facing API) and the effort involved. Hopefully, at some point, Salesforce will fix this issue.
JavaScript Remote Objects and the Lightning Data Service are designed to expose a "SOQL- and DML-like API" for use by the JavaScript code embedded within a Visualforce page or Lightning Component. Providing a way to query and update the database without having to go through the traditional AJAX Toolkit or Salesforce REST API's that incur charges to the daily API limit.
Visualforce Developer's Guide has an excellent topic that describes the best practices around using this feature, entitled Best Practices for Using Remote Objects, which I highly recommend that you read and digest fully. The Lighting Component developer Guide also has samples describing the Lightning Data Service. The main aspect from this section which I would like to highlight is the one that relates to transactional boundaries in close conjunction with maintaining a good Separation of Concerns.
Resist the temptation to invoke multiple database operations within a single JavaScript code block as each will be executed in its own Salesforce execution context and thus transaction. This means that, if an error occurs in your JavaScript code, previous operations will not be rolled back.
If you find yourself in this situation, it is also likely that you should be positioning such code in your application's Service layer and thus using JavaScript Remoting to call that Service layer method, which will then occur within a single transactional scope.
That said, if you have use cases that result in a single database operation then you can of course consider using this feature, safely assured that your Apex Trigger and Domain layer code will continue to enforce your data validation and integrity.
Finally, note that querying records from JavaScript does not invoke your Selector code. So the fields queried and populated in the resulting SObject records on the client will not always be the same in all cases throughout your JavaScript code.
18.191.62.122