Tell Me More: About the Code
The Apex class is the controller for the Visualforce page, and uses the @RemoteAction annotation on the methods. When you use this annotation, the Visualforce page wraps the logic in a JavaScript-friendly way. This is known as Visualforce remoting.
Visualforce remoting allows for quick and tight integration between Apex and JavaScript. This communication model works asynchronously as opposed to the synchronous model in the traditional Visualforce/Apex MVC paradigm. So after passing parameters into your controller, you can get the result from a response handler function, and write any additional client-side logic before doing any DOM manipulation or building your page with mobile templates or frameworks.
Visualforce remoting is ideal for mobile developers on the Salesforce App Cloud because it simplifies the direct server-side access to Salesforce objects and allows you to use Apex tools such as SOQL, Apex methods, and so on for rapid platform development. And, you don’t have to deal with view state, which makes pages perform better.
Apex Class QuickOrderController
This class uses Visualforce remoting and contains the logic called by the Visualforce page to find warehouses and create orders and line items.
1global class QuickOrderController{
2 public static List<Merchandise__c> merchandise;
3 public static Line_Item__c quickOrder;
4
5
6 public QuickOrderController(ApexPages.
7 StandardController controller){
8 }
9
10 @RemoteAction
11 global static List<Merchandise__c> findWarehouses(String accId,
12 String merchName, String warehouseDist){
13 merchandise = new List<Merchandise__c>();
14 String queryString = '';
15 String queryName = '%' + merchName + '%';
16
17 Account acc = [Select Location__Longitude__s,
18 Location__Latitude__s, Name, Id
19 from Account where Id =: accId];
20
21 //Finds warehouses nearby if you have location
22 //specified on the Account
23 if(acc.Location__Latitude__s != null &&
24 acc.Location__Longitude__s != null){
25 queryString = 'SELECT Id, (SELECT Id, Name, Quantity__c,
26 Warehouse__r.Name, Warehouse__r.Id,
27 Warehouse__r.Street_Address__c,
28 Warehouse__r.City__c '+
29 'FROM Merchandise__r WHERE Name
30 like :queryName) '
31 +'FROM Warehouse__c WHERE '
32 +'DISTANCE(Location__c, GEOLOCATION('
33 +acc.Location__Latitude__s+','
34 +acc.Location__Longitude__s+'), \'mi\')';
35 if(warehouseDist != null){
36 queryString += ' <'+ warehouseDist;
37 }
38
39 }
40 //If no location defined on the Account, this will run
41 //query against the merchandise name only
42 else {
43 queryString = 'SELECT Id, Name,
44 Location__Longitude__s,
45 Location__Latitude__s, '
46 +'(SELECT Id, Name, Warehouse__r.Name,
47 Quantity__c
48 FROM Merchandise__r WHERE Name
49 like :queryName) '
50 +'FROM Warehouse__c limit 25';
51
52 }
53
54 //This creates a list of merchandise
55 //to display in the search results
56 Warehouse__c[] warehouses = Database.Query(queryString);
57 for(Warehouse__c warehouse : warehouses){
58 Merchandise__c[] merch =
59 warehouse.getSObjects('Merchandise__r');
60 if (merch != null) {
61 for (Merchandise__c m : merch){
62 merchandise.add(m);
63 }
64 }
65 }
66 return merchandise;
67
68 }
69
70 //This remote action creates the invoice for the quick order
71 @RemoteAction
72 global static Line_Item__c createQuickOrder(
73 String accId, String merchandiseId){
74 Invoice__c newInvoice = new Invoice__c();
75 newInvoice.Account__c = accId;
76 insert newInvoice;
77
78 quickOrder = new Line_Item__c();
79 Merchandise__c m = [Select Id, Name from Merchandise__c
80 where Id=: merchandiseId limit 1];
81 quickOrder.Merchandise__c = m.Id;
82 quickOrder.Invoice__c = newInvoice.Id;
83
84 return quickOrder;
85 }
86
87 //This remote action creates the line item related to the
88 //invoice for the quick order
89 @RemoteAction
90 global static Boolean insertQuickOrder(String o, String q){
91 try {
92 Integer quantity = integer.valueof(q);
93
94 Line_Item__c order = new Line_Item__c();
95 /* The order variable being passed in as a param is being
96 passed in the form of a JSON object. You need to use
97 the JSON deserialize method in Apex to convert it
98 into a SObject */
99 order = (Line_Item__c)JSON.deserialize(
100 o, Line_Item__c.class);
101
102 order.Quantity__c = quantity;
103 insert order;
104
105 //Need to requery for the name for the post to chatter
106 //since it wasn't explicitly specified
107 Line_Item__c li = [Select Name, Merchandise__r.Name, Id,
108 Quantity__c, Invoice__c from Line_Item__c
109 where Id =: order.Id];
110
111 FeedItem post = new FeedItem();
112 post.ParentId = aId;
113 post.Body = UserInfo.getName() + ' just created a quick order';
114 post.type = 'LinkPost';
115 post.LinkUrl = '/' + li.Invoice__c;
116 post.Title = li.Merchandise__r.Name + ': ' + li.quantity__c;
117 insert post;
118 } catch(System.Exception ex) {
119 system.debug(ex.getMessage());
120 }
121 return true;
122 }
123
124 //This remote action handles deleting the invoice if
125 //the user doesn't want to insert the line item
126 @RemoteAction
127 global static Boolean goBack(String invoiceId){
128 // Delete created invoice and return to original
129 //search screen
130 Invoice__c cancelledInvoice = [select Id from Invoice__c
131 where Id=: invoiceId];
132 delete cancelledInvoice;
133
134 return true;
135 }
136
137}1FeedItem post = new FeedItem();
2 post.ParentId = aId;
3 post.Body = UserInfo.getName() + ' just created a quick order';
4 post.type = 'LinkPost';
5 post.LinkUrl = '/' + li.Invoice__c;
6 post.Title = li.Merchandise__r.Name + ': ' + li.quantity__c;
7 insert post;Visualforce Page QuickOrderPage
This page calls the controller with the user input and then displays the merchandise and warehouse information to the user. If the user wants to create an order, this page also calls the controller to create the order associated with the customer account and add a line item. At the beginning of the page, the code also does some styling of the page using the Salesforce mobile design templates.
1<apex:page standardController="Account"
2 extensions="QuickOrderController" docType="html-5.0"
3 standardStylesheets="false" showheader="false" sidebar="false">
4
5 <!--Include stylesheets for the mobile look and feel -->
6 <apex:stylesheet value="{!URLFOR(
7 $Resource.Mobile_Design_Templates,
8 'Mobile-Design-Templates-master/
9 common/css/app.min.css')}"/>
10 <apex:includeScript value="{!URLFOR(
11 $Resource.Mobile_Design_Templates,
12 'Mobile-Design-Templates-master/common/js/
13 jQuery2.0.2.min.js')}"/>
14 <apex:includeScript value="{!URLFOR(
15 $Resource.Mobile_Design_Templates,
16 'Mobile-Design-Templates-master/common/js/
17 jquery.touchwipe.min.js')}"/>
18 <apex:includeScript value="{!URLFOR(
19 $Resource.Mobile_Design_Templates,
20 'Mobile-Design-Templates-master/common/
21 js/main.min.js')}"/>
22
23 <style>
24 /* Default S1 color styles */
25 .list-view-header, .data-capture-buttons a {
26 background: -webkit-linear-gradient(
27 #2a93d5,#107abb);
28 background: linear-gradient(#2a93d5,#107abb);
29 box-shadow: 0 1px 3px rgba(0,0,0,.2),
30 inset 0 1px 0 rgba(255,255,255,.21);
31 color: white;
32 font-weight: bold;
33 }
34
35 #resultPage, #searchPage {
36 padding-bottom: 50px;
37 }
38 </style>The QuickOrderPage also calls the Force.com Canvas SDK to enable the publisher Submit button and close the publisher window.
1<!-- This needs to be included so the publisher can be used
2 to submit the action -->
3<script type='text/javascript' src='/canvas/sdk/js/publisher.js'></script>1//This method will activate the publish button
2//so the form can be submitted
3Sfdc.canvas.publisher.publish({
4 name: "publisher.setValidForSubmit",
5 payload:"true"});1<script type='text/javascript'>
2 Sfdc.canvas.publisher.subscribe({name: "publisher.post",
3 onData:function(e) {
4 //This subscribe fires when the user hits
5 //Submit in the publisher
6 insertQuickOrder();
7 }});
8</script>1// Success - close the publisher and refresh the feed
2Sfdc.canvas.publisher.publish({name: "publisher.close",
3 payload:{ refresh:"true"}});