Apex コントローラの JavaScript Remoting
- JavaScript で記述される、Visualforce ページに追加するリモートメソッドの呼び出し。
- Apex コントローラクラスのリモートメソッド定義。このメソッドは Apex で記述されますが、通常の action メソッドとはいくつかの違いがあります。
- JavaScript で記述される、Visualforce ページに追加または含めるレスポンスハンドラコールバック関数。
Visualforce ページへの JavaScript Remoting の追加
1[namespace.]controller.method(
2
3 [parameters...,]
4
5 callbackFunction,
6
7 [configuration]
8
9);- namespace はコントローラクラスの名前空間です。組織に名前空間が定義されている場合、またはクラスがインストール済みパッケージに基づく場合は必須です。
- controller は Apex コントローラの名前です。
- method はコールする Apex メソッドの名前です。
- parameters はメソッドが取るパラメータのカンマ区切りのリストです。
- callbackFunction はコントローラからの応答を処理する JavaScript 関数の名前です。匿名関数をインラインで宣言することもできます。callbackFunction ではメソッドコールの状況と結果をパラメータとして返します。
- configuration は、リモートコールと応答の処理を設定します。Apex メソッドの応答をエスケープするかどうかを指定するなど、リモートコールの動作を変更する場合にこれを使用します。
リモートメソッドコールは同期して実行されますが、応答が返されるのを待機しません。応答が返されると、コールバック関数は非同期で応答を処理します。詳細は、「リモート応答の処理」を参照してください。
JavaScript Remoting 要求の設定
1{ buffer: true, escape: true, timeout: 30000 }| 名前 | データ型 | 説明 |
|---|---|---|
| buffer | Boolean | 相互に近い時間に実行される要求を 1 つの要求にグループ化するかどうかを指定します。デフォルトは、true です。 JavaScript Remoting では、相互に近い時間に実行される複数の要求を最適化し、これらを 1 つの要求にグループ化します。このバッファリングにより、要求および応答のサイクルの全体的な効率性が改善されますが、場合によってはすべての要求が個別に実行されるようにする方が便利なこともあります。 |
| escape | Boolean | Apex メソッドの応答をエスケープするかどうかを指定します。デフォルトは、true です。 |
| timeout | Integer | 要求のタイムアウト (ミリ秒単位)。デフォルトは 30000 (30 秒) です。最大値は 120000 (120 秒 = 2 分) です。 |
1<script type="text/javascript">
2
3
4
5 Visualforce.remoting.timeout = 120000; // Set timeout at page level
6
7
8
9 function getRemoteAccount() {
10
11 var accountName = document.getElementById('acctSearch').value;
12
13
14
15 // This remoting call will use the page's timeout value
16
17 Visualforce.remoting.Manager.invokeAction(
18
19 '{!$RemoteAction.AccountRemoter.getAccount}',
20
21 accountName,
22
23 handleResult
24
25 );
26
27 }
28
29
30
31 function handleResult(result, event) { ... }
32
33</script>ページレベルのタイムアウト設定を要求単位で上書きするには、その要求の設定オブジェクトのタイムアウトを、上記の説明に従って設定します。
JavaScript Remoting の OAuth 2.0 認証
JavaScript Remoting 要求では、認証に標準のユーザ名とパスワードによるログインプロセスではなく、OAuth 2.0 を使用できます。OAuth では、標準の認証ではセキュアに実行できないアプリケーション間および組織間統合が可能です。
Visualforce ページでは、認証用の OAuth がページレベルで設定され、すべての JavaScript Remoting 要求に OAuth が使用されます。設定を除き、JavaScript Remoting の使用法はまったく同じです。
1<script type="text/javascript">
2
3
4
5 Visualforce.remoting.oauthAccessToken = <access_token>;
6
7
8
9 // ...
10
11</script>oauthAccessToken は、ページのコードで取得される OAuth 認証トークンです。アクセストークンの取得と更新は簡単な OAuth で直接行われ、追加部分が 1 つ��ります。JavaScript Remoting の OAuth 認証では "visualforce" スコープが要求されるため、このスコープを使用するか、これを含むスコープ ("web" や "full") を使用してトークンを生成する必要があります。OAuth 要求で、scope=visualforce (あるいは "web" または "full") と設定します。
アクセストークンの取得および Force.com プラットフォームでの OAuth の使用についての詳細は、Salesforce オンラインヘルプの「リモートアクセスアプリケーションの認証」、および developer.salesforce.com/page/Digging_Deeper_into_OAuth_2.0_on_Force.com を参照してください。
名前空間および JavaScript Remoting
1Visualforce.remoting.Manager.invokeAction(
2
3 'fully_qualified_remote_action',
4
5 invocation_parameters
6
7);完全修飾リモートアクションは、namespace[.BaseClass][.ContainingClass].ConcreteClass.Method のように、名前空間、ベースクラスなどを含むリモートアクションメソッドへの完全なパスを表す文字列です。名前空間を自動的に解決するには、たとえば、{!$RemoteAction.MyController.getAccount} のように、式に $RemoteAction を使用します。
- @RemoteAction メソッドに送信するためのパラメータ (ある場合)。
- 返される結果を処理するコールバック関数。
- 呼び出しに関する設定詳細 (ある場合)。
1<script type="text/javascript">
2
3function getRemoteAccount() {
4
5 var accountName = document.getElementById('acctSearch').value;
6
7
8
9 Visualforce.remoting.Manager.invokeAction(
10
11 '{!$RemoteAction.MyController.getAccount}',
12
13 accountName,
14
15 function(result, event){
16
17 if (event.status) {
18
19 document.getElementById('acctId').innerHTML = result.Id
20
21 document.getElementById('acctName').innerHTML = result.Name;
22
23 } else if (event.type === 'exception') {
24
25 document.getElementById("responseErrors").innerHTML = event.message;
26
27 } else {
28
29 document.getElementById("responseErrors").innerHTML = event.message;
30
31 }
32
33 },
34
35 {escape: true}
36
37 );
38
39}
40
41</script>リモートメソッドの宣言
1@RemoteAction
2
3global static String getItemId(String objectName) { ... }メソッドでは、引数として、Apex プリミティブ、コレクション、型指定された sObject、汎用 sObject、ユーザ定義された Apex クラスおよびインターフェースを取ることができます。汎用 sObject では、実際の型を特定するために ID または sobjectType の値を指定する必要があります。インターフェースパラメータでは、実際の型を特定するために apexType を指定する必要があります。
メソッドでは Apex プリミティブ、sObject、コレクション、ユーザ定義された Apex クラスおよび列挙、SaveResult、UpsertResult、DeleteResult、SelectOption、または PageReference を返すことができます。
- getItemIdFromName(String objectName)
- getItemIdFromProductNumber(Integer productNumber)
| @RemoteAction のスコープ | Visualforce Page | 非グローバルコンポーネント | グローバルコンポーネント | iframe |
|---|---|---|---|---|
| グローバルリモートメソッド | 使用可能 | 使用可能 | 使用可能 | 使用可能 |
| 公開リモートメソッド | 使用可能 | 使用可能 | エラー | エラー |
| 最上位コンテナ | ||||
|---|---|---|---|---|
| @RemoteAction のアクセス元 | Visualforce Page | 非グローバルコンポーネント | グローバルコンポーネント | iframe |
| グローバルコンポーネント | 使用可能 | 使用可能 | 使用可能 | 使用可能 |
| 非グローバルコンポーネント | 使用可能 | 使用可能 | 非グローバルコンポーネントが公開リモートメソッドを含まない場合にのみ使用可能。 | 非グローバルコンポーネントが公開リモートメソッドを含まない場合にのみ使用可能。 |
| <apex:include> <apex:composition> | 同じ名前空間内では使用可能。名前空間が異なる場合および含まれるページまたはその子階層に公開リモートメソッドが含まれる場合はエラー。 | なし | なし | エラー |
リモートメソッドと継承
@RemoteAction メソッドが検索またはコールされる場合、Visualforce ではページコントローラの継承階層を調べ、コントローラの上位階層のクラス内で @RemoteAction メソッドを検索します。
1global with sharing class ChildRemoteController
2
3 extends ParentRemoteController { }
4
5global virtual with sharing class ParentRemoteController
6
7 extends GrandparentRemoteController { }
8
9
10
11global virtual with sharing class GrandparentRemoteController {
12
13 @RemoteAction
14
15 global static String sayHello(String helloTo) {
16
17 return 'Hello ' + helloTo + ' from the Grandparent.';
18
19 }
20
21}1swfobject.registerObject("clippy.codeblock-8", "9");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<apex:page controller="ChildRemoteController" >
18
19 <script type="text/javascript">
20
21 function sayHello(helloTo) {
22
23 ChildRemoteController.sayHello(helloTo, function(result, event){
24
25 if(event.status) {
26
27 document.getElementById("result").innerHTML = result;
28
29 }
30
31 });
32
33 }
34
35 </script>
36
37
38
39 <button onclick="sayHello('Jude');">Say Hello</button><br/>
40
41 <div id="result">[Results]</div>
42
43
44
45</apex:page>インターフェースパラメータによるリモートメソッドの宣言
具象クラスに制限するのではなく、インターフェースパラメータと戻り値のデータ型を使用して @RemoteAction メソッドを宣言できます。これにより、たとえば、パッケージプロバイダは、リモートメソッドと関連付けられたインターフェースをパッケージ化できます。登録者組織は、パッケージ化されたインターフェースを実装する独自のクラスに渡すことによって、Visualforce ページからコールできます。
1public class RemoteController {
2
3 public interface MyInterface { String getMyString(); }
4
5 public class MyClass implements MyInterface {
6
7 private String myString;
8
9 public String getMyString() { return myString; }
10
11 public void setMyString(String s) { myString = s; }
12
13 }
14
15
16
17 @RemoteAction
18
19 public static MyInterface setMessage(MyInterface i) {
20
21 MyClass myC = new MyClass();
22
23 myC.setMyString('MyClassified says "' + i.getMyString() + '".');
24
25 return myC;
26
27 }
28
29}1Visualforce.remoting.Manager.invokeAction(
2
3 '{!$RemoteAction.RemoteController.setMessage}',
4
5 {'apexType':'thenamespace.RemoteController.MyClass', 'myString':'Lumos!'},
6
7 handleResult
8
9);リモート応答の処理
リモートメソッドコールに対する応答は、リモートメソッドコールで提供されているコールバック関数によって非同期に処理されます。コールバック関数は、リモートコールの状況を表す event オブジェクト、およびリモート Apex メソッドで返される result オブジェクトをパラメータとして取得します。関数は返されるデータに基づいてページの情報およびユーザインターフェース要素を更新できます。
- event.status は、成功のときは true、エラーのときは false になります。
- event.type は応答の種別です。成功したコールは rpc、リモートメソッドが例外を返した場合は exception のようになります。
- event.message には、返されたエラーメッセージが含まれます。
- event.where には、リモートメソッドにより生成された場合は、Apex スタック追跡が含まれます。
string または number など、result によって返される Apex プリミティブデータ型は対応する JavaScript に変換されます。返される Apex オブジェクトは JavaScript オブジェクトに変換され、コレクションは JavaScript 配列に変換されます。JavaScript は大文字と小文字を区別することに注意してください。そのため、id、Id、および ID は異なる項目であるとみなされます。
JavaScript リモートコールの一部として、Apex メソッド応答に同じオブジェクトに対する参照が含まれる場合、そのオブジェクトは返される JavaScript オブジェクトには複製されません。代わりに、表示される JavaScript オブジェクトには同じオブジェクトへの参照が含まれます。たとえば、同一オブジェクトを 2 回含むリストを返す Apex メソッドです。
デフォルトでは、リモートコールの応答は、30 秒以内に返される必要があります。これを超えると、コールはタイムアウトになります。要求の完了にこれ以上の時間を必要とする場合は、長いタイムアウトを 120 秒以内で設定します。
- 各要求の応答サイズを削減する。必要なデータのみを返します。
- 大量データの取得を、小さなチャンクを返す複数の要求に分割する。
- バッチ以外の要求を使用していることを確認する。Remoting 要求の設定ブロックで { buffer: false } と設定します。
- バッチ要求の使用頻度を抑え、バッチサイズを削減する。
1swfobject.registerObject("clippy.codeblock-12", "9");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<script type="text/javascript">
18
19function getRemoteAccount() {
20
21 var accountName = document.getElementById('acctSearch').value;
22
23
24
25 Visualforce.remoting.Manager.invokeAction(
26
27 '{!$RemoteAction.MyController.getAccount}',
28
29 accountName,
30
31 function(result, event){
32
33 if (event.status) {
34
35 document.getElementById('acctId').innerHTML = result.Id
36
37 document.getElementById('acctName').innerHTML = result.Name;
38
39 } else if (event.type === 'exception') {
40
41 document.getElementById("responseErrors").innerHTML =
42
43 event.message + "<br/>\n<pre>" + event.where + "</pre>";
44
45 } else {
46
47 document.getElementById("responseErrors").innerHTML = event.message;
48
49 }
50
51 }
52
53 );
54
55}
56
57</script>JavaScript Remoting および <apex:actionFunction>
-
<apex:actionFunction> タグ
- ユーザが再表示ターゲットを指定できる
- フォームを送信する
- JavaScript の記述は不要
- JavaScript Remoting:
- ユーザがパラメータを渡すことができる
- コールバックを提供する
- 一部の JavaScript を記述する必要がある
通常、<apex:actionFunction> の方が使いやすく、必要なコードも少なくなります。一方、JavaScript では、より高度な柔軟性を提供できます。