リモートオブジェクトと jQuery Mobile の併用例
Visualforce リモートオブジェクトは、JavaScript フレームワークとうまく「融合」できるように設計されています。次の例は、拡張されていますが単純であり、リモートオブジェクトと jQuery Mobile を使用して取引先責任者のリストを表示し、取引先責任者の追加、編集、および削除を行います。
次の例は Salesforce モバイルパックの jQuery Mobile を使用し、jQuery 用モバイルパックに含まれているサンプルコードに基づいています。リモートオブジェクトと jQuery Mobile により、携帯端末向けの単純な取引先責任者管理ページを簡単に作成できます。
リモートオブジェクトと jQuery Mobile を使用した単純な取引先責任者エディタ
1<apex:page docType="html-5.0" showHeader="false" sidebar="false">
2
3
4
5 <!-- Include jQuery and jQuery Mobile from the Mobile Pack -->
6
7 <apex:stylesheet value="{!URLFOR($Resource.MobilePack_jQuery,
8
9 'jquery.mobile-1.3.0.min.css')}"/>
10
11 <apex:includeScript value="{!URLFOR($Resource.MobilePack_jQuery,
12
13 'jquery-1.9.1.min.js')}"/>
14
15 <apex:includeScript value="{!URLFOR($Resource.MobilePack_jQuery,
16
17 'jquery.mobile-1.3.0.min.js')}"/>
18
19
20
21 <!-- Remote Objects declaration -->
22
23 <apex:remoteObjects jsNamespace="RemoteObjectModel">
24
25 <apex:remoteObjectModel name="Contact" fields="Id,FirstName,LastName,Phone">
26
27 <!-- Notes is a custom field added to the Contact object -->
28
29 <apex:remoteObjectField name="Notes__c" jsShorthand="Notes"/>
30
31 </apex:remoteObjectModel>
32
33 </apex:remoteObjects>
34
35
36
37 <head>
38
39 <title>Contacts</title>
40
41 <meta name="viewport"
42
43 content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
44
45
46
47 <script type="text/javascript">
48
49 var $j = jQuery.noConflict();
50
51
52
53 // Config object with commonly used data
54
55 // This keeps some hard-coded HTML IDs out of the code
56
57 var Config = {
58
59 Selectors: {
60
61 list: '#cList',
62
63 detailFields: "#fName #lName #phone #notes #error #contactId".split(" ")
64
65 },
66
67 Data: {
68
69 contact: 'contact'
70
71 }
72
73 };
74
75
76
77 // Get all contacts, and display them in a list
78
79 function getAllContacts() {
80
81 $j.mobile.showPageLoadingMsg();
82
83
84
85 var c = new RemoteObjectModel.Contact();
86
87 // Use the 'limit' operator to increase the default limit of 20
88
89 c.retrieve({ limit: 100 }, function (err, records) {
90
91 // Handle any errors
92
93 if (err) {
94
95 displayError(err);
96
97 } else {
98
99 // Empty the current list
100
101 var list = $j(Config.Selectors.list).empty();
102
103 // Now add results records to list
104
105 $j.each(records, function() {
106
107 var newLink = $j('<a>'+ this.get('FirstName')+ ' ' +
108
109 this.get('LastName')+ '</a>');
110
111 newLink.data(Config.Data.contact, this.get('Id'));
112
113 newLink.appendTo(list).wrap('<li></li>');
114
115 });
116
117
118
119 $j.mobile.hidePageLoadingMsg();
120
121 list.listview('refresh');
122
123 }
124
125 });
126
127 }
128
129
130
131 // Handle the Save button that appears on both
132
133 // the Edit Contact and New Contact pages
134
135 function addUpdateContact(e){
136
137 e.preventDefault();
138
139
140
141 var record = new RemoteObjectModel.Contact({
142
143 FirstName: $j('#fName').val(),
144
145 LastName: $j('#lName').val(),
146
147 Phone: $j('#phone').val(),
148
149 Notes: $j('#notes').val()
150
151 // Note use of shortcut 'Notes' in place of Notes__c
152
153 });
154
155
156
157 var cId = $j('#contactId').val();
158
159 if( !cId ) { // new record
160
161 record.create(updateCallback);
162
163 } else { // update existing
164
165 record.set('Id', cId);
166
167 record.update(updateCallback);
168
169 }
170
171 }
172
173
174
175 // Handle the delete button
176
177 function deleteContact(e){
178
179 e.preventDefault();
180
181 var ct = new RemoteObjectModel.Contact();
182
183 ct.del($j('#contactId').val(), updateCallback);
184
185 }
186
187
188
189 // Callback to handle DML Remote Objects calls
190
191 function updateCallback(err, ids){
192
193 if (err) {
194
195 displayError(err);
196
197 } else {
198
199 // Reload the contacts with current list
200
201 getAllContacts();
202
203 $j.mobile.changePage('#listpage', {changeHash: true});
204
205 }
206
207 }
208
209
210
211 // Utility function to log and display any errors
212
213 function displayError(e){
214
215 console && console.log(e);
216
217 $j('#error').html(e.message);
218
219 }
220
221
222
223 // Attach functions to the buttons that trigger them
224
225 function regBtnClickHandlers() {
226
227 $j('#add').click(function(e) {
228
229 e.preventDefault();
230
231 $j.mobile.showPageLoadingMsg();
232
233
234
235 // empty all the clic handlers
236
237 $j.each(Config.Selectors.detailFields, function(i, field) {
238
239 $j(field).val('');
240
241 });
242
243
244
245 $j.mobile.changePage('#detailpage', {changeHash: true});
246
247 $j.mobile.hidePageLoadingMsg();
248
249 });
250
251
252
253 $j('#save').click(function(e) {
254
255 addUpdateContact(e);
256
257 });
258
259
260
261 $j('#delete').click(function(e) {
262
263 deleteContact(e);
264
265 });
266
267 }
268
269
270
271 // Shows the contact detail view,
272
273 // including filling in form fields with current data
274
275 function showDetailView(contact) {
276
277 $j('#contactId').val(contact.get('Id'));
278
279 $j('#fName').val(contact.get('FirstName'));
280
281 $j('#lName').val(contact.get('LastName'));
282
283 $j('#phone').val(contact.get('Phone'));
284
285 $j('#notes').val(contact.get('Notes'));
286
287 $j('#error').html('');
288
289 $j.mobile.changePage('#detailpage', {changeHash: true});
290
291 }
292
293
294
295 // Register click handler for list view clicks
296
297 // Note: One click handler handles the whole list
298
299 function regListViewClickHandler() {
300
301 $j(Config.Selectors.list).on('click', 'li', function(e) {
302
303
304
305 // show loading message
306
307 $j.mobile.showPageLoadingMsg();
308
309
310
311 // get the contact data for item clicked
312
313 var id = $j(e.target).data(Config.Data.contact);
314
315
316
317 // retrieve latest details for this contact
318
319 var c = new RemoteObjectModel.Contact();
320
321 c.retrieve({
322
323 where: { Id: { eq: id } }
324
325 }, function(err, records) {
326
327 if(err) {
328
329 displayError(err);
330
331 } else {
332
333 showDetailView(records[0]);
334
335 }
336
337
338
339 // hide the loading message in either case
340
341 $j.mobile.hidePageLoadingMsg();
342
343 });
344
345 });
346
347 }
348
349
350
351 // And, finally, run the page
352
353 $j(document).ready(function() {
354
355 regBtnClickHandlers();
356
357 regListViewClickHandler();
358
359 getAllContacts();
360
361 });
362
363
364
365 </script>
366
367 </head>
368
369
370
371 <!-- HTML and jQuery Mobile markup for the list and detail screens -->
372
373 <body>
374
375
376
377 <!-- This div is the list "page" -->
378
379 <div data-role="page" data-theme="b" id="listpage">
380
381 <div data-role="header" data-position="fixed">
382
383 <h2>Contacts</h2>
384
385 <a href='#' id="add" class='ui-btn-right' data-icon='add'
386
387 data-theme="b">Add</a>
388
389 </div>
390
391 <div data-role="content" id="contactList">
392
393 <ul id="cList" data-filter="true" data-inset="true"
394
395 data-role="listview" data-theme="c" data-dividertheme="b">
396
397 </ul>
398
399 </div>
400
401 </div>
402
403
404
405 <!-- This div is the detail "page" -->
406
407 <div data-role="page" data-theme="b" id="detailpage">
408
409 <div data-role="header" data-position="fixed">
410
411 <a href='#listpage' id="back2ContactList" class='ui-btn-left'
412
413 data-icon='arrow-l' data-direction="reverse"
414
415 data-transition="flip">Back</a>
416
417 <h1>Contact Details</h1>
418
419 </div>
420
421 <div data-role="content">
422
423 <div data-role="fieldcontain">
424
425 <label for="fName">First Name:</label>
426
427 <input name="fName" id="fName" />
428
429 </div>
430
431 <div data-role="fieldcontain">
432
433 <label for="lName">Last Name:</label>
434
435 <input name="lName" id="lName" />
436
437 </div>
438
439 <div data-role="fieldcontain">
440
441 <label for="phone">Phone:</label>
442
443 <input name="phone" id="phone"/>
444
445 </div>
446
447 <div data-role="fieldcontain">
448
449 <label for="notes">Notes:</label>
450
451 <textarea name="notes" id="notes"/>
452
453 </div>
454
455
456
457 <h2 style="color:red" id="error"></h2>
458
459
460
461 <input type="hidden" id="contactId" />
462
463 <button id="save" data-role="button" data-icon="check"
464
465 data-inline="true" data-theme="b" class="save">Save</button>
466
467 <button id="delete" data-role="button" data-icon="delete"
468
469 data-inline="true" class="destroy">Delete</button>
470
471 </div>
472
473 </div>
474
475 </body>
476
477</apex:page>4 つのリモートオブジェクト操作すべてが使用されていますが、コールバックハンドラは 3 つしかありません。
- getAllContacts() は retrieve() をコールして取引先責任者のリストを読み込み、コールバック用の匿名関数を提供します。コールバックは、エラーがないかチェックし、結果を反復処理してページに追加します。
- ���様に、showDetailView() は retrieve() をコールして詳細ページ用に 1 件の取引先責任者を読み込み、結果は再び匿名関数によって処理されます。
- addUpdateContact() と deleteContact() は、取引先責任者の追加、更新、および削除を処理します。どちらのメソッドも updateCallback() をコールバック関数として渡します。updateCallback() はリモートオブジェクト操作の結果を使用しません。エラーのチェックを行い、エラーをコンソールにログ出力し、getAllContacts() をコールしてページを更新するのみです。