この文章は Salesforce 機械翻訳システムを使用して翻訳されました。詳細はこちらをご参照ください。
英語に切り替える

Apex コントローラの JavaScript Remoting

JavaScript から Apex コントローラのメソッドをコールするには、VisualforceJavaScript Remoting を使用します。これにより、AJAX 機能を実装した標準 Visualforce コンポーネントでは実現できない、複雑で動的な動作を行うページを作成できます。
JavaScript Rmoting は、次の 3 つで構成されています。
  • JavaScript で記述される、Visualforce ページに追加するリモートメソッドの呼び出し。
  • Apex コントローラクラスのリモートメソッド定義。このメソッドは Apex で記述されますが、通常の action メソッドとはいくつかの違いがあります。
  • JavaScript で記述される、Visualforce ページに追加または含めるレスポンスハンドラコールバック関数。

Visualforce ページへの JavaScript Remoting の追加

Visualforce ページで JavaScript Remoting を使用するには、要求を次の形式の JavaScript 呼び出しとして追加します。
1[namespace.]controller.method(
2
3    [parameters...,]
4
5    callbackFunction,
6
7    [configuration]
8
9);
  • namespace はコントローラクラスの名前空間です。組織に名前空間が定義されている場合、またはクラスがインストール済みパッケージに基づく場合は必須です。
  • controllerApex コントローラの名前です。
  • method はコールする Apex メソッドの名前です。
  • parameters はメソッドが取るパラメータのカンマ区切りのリストです。
  • callbackFunction はコントローラからの応答を処理する JavaScript 関数の名前です。匿名関数をインラインで宣言することもできます。callbackFunction ではメソッドコールの状況と結果をパラメータとして返します。
  • configuration は、リモートコールと応答の処理を設定します。Apex メソッドの応答をエスケープするかどうかを指定するなど、リモートコールの動作を変更する場合にこれを使用します。

リモートメソッドコールは同期して実行されますが、応答が返されるのを待機しません。応答が返されると、コールバック関数は非同期で応答を処理します。詳細は、リモート応答の処理を参照してください。

JavaScript Remoting 要求の設定

Remoting 要求の宣言時に構成設定を使用してオブジェクトを指定することで、Remoting 要求を設定します。たとえば、デフォルトの設定パラメータは次のようになります。
1{ buffer: true, escape: true, timeout: 30000 }
これらの設定パラメータに順序はありません。また、デフォルトから変更の必要がないパラメータは省略できます。
JavaScript Remoting では、次の設定パラメータをサポートしています。
名前 データ型 説明
buffer Boolean 相互に近い時間に実行される要求を 1 つの要求にグループ化するかどうかを指定します。デフォルトは、true です。

JavaScript Remoting では、相互に近い時間に実行される複数の要求を最適化し、これらを 1 つの要求にグループ化します。このバッファリングにより、要求および応答のサイクルの全体的な効率性が改善されますが、場合によってはすべての要求が個別に実行されるようにする方が便利なこともあります。

escape Boolean Apex メソッドの応答をエスケープするかどうかを指定します。デフォルトは、true です。
timeout Integer 要求のタイムアウト (ミリ秒単位)。デフォルトは 30000 (30 秒) です。最大値は 120000 (120 秒 = 2 分) です。
Visualforce Remoting オブジェクトを使用してタイムアウトを設定することで、ページで行われるすべての要求に対して要求タイムアウトを設定することもできます。
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 の使用法はまったく同じです。

Visualforce ページから JavaScript Remoting 用の OAuth を設定するには、次のようにします。
1<script type="text/javascript">
2
3
4
5    Visualforce.remoting.oauthAccessToken = <access_token>;
6
7
8
9    // ...
10
11</script>
oauthAccessToken を一度設定すると、すべての JavaScript Remoting 要求で OAuth が使用されます。残りの JavaScript Remoting コードには変更は必要ありません。

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

特にパッケージで提供されるメソッドに Remotoing コールを行うページで名前空間との連携をより簡単に行うため、$RemoteAction グローバル変数を使用して、リモートアクションの正しい名前空間 (ある場合) を自動的に解決できます。この機能を使用するには、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>
この JavaScript Remoting コールでは、コントローラが定義されている名前空間、自分の名前空間内にあるか、インストールされたパッケージが提供する名前空間内にあるなどの詳細を把握している必要がありません。また、組織に定義済みの名前空間がない状況にも対応します。

invokeAction のコール時に発生したエラーは JavaScript コンソールでのみレポートされます。たとえば、$RemoteAction で複数の名前空間に一致する @RemoteAction メソッドが見つかった場合、最初に一致したメソッドを返し、JavaScript コンソールに警告を記録します。一致するコントローラまたはアクションが見つからない場合は、そのコールはエラーを表示することなく失敗し、エラーは JavaScript コンソールに記録されます。

メモ

リモートメソッドの宣言

コントローラでは、Apex のメソッド宣言は、次のように @RemoteAction アノテーションが先頭に付加されます。
1@RemoteAction
2
3global static String getItemId(String objectName) { ... }

メソッドでは、引数として、Apex プリミティブ、コレクション、型指定された sObject、汎用 sObject、ユーザ定義された Apex クラスおよびインターフェースを取ることができます。汎用 sObject では、実際の型を特定するために ID または sobjectType の値を指定する必要があります。インターフェースパラメータでは、実際の型を特定するために apexType を指定する必要があります。

メソッドでは Apex プリミティブ、sObject、コレクション、ユーザ定義された Apex クラスおよび列挙、SaveResultUpsertResultDeleteResultSelectOption、または PageReference を返すことができます。

JavaScript Remoting に使用されるメソッドは、名前とパラメータ数によって一意に識別される必要があります。オーバーロードは不可能です。たとえば、上記のメソッドでは、一緒に getItemId(Integer productNumber) メソッドを持つことはできません。代わりに、異なる名前で複数のメソッドを宣言します。
  • getItemIdFromName(String objectName)
  • getItemIdFromProductNumber(Integer productNumber)
Apex メソッドは static で、かつ global または public のいずれかである必要があります。グローバルに公開されるリモートアクションで繊細な操作を実行したり、非公開のデータを公開したりしないようにしてください。global リモートアクションは他の global メソッドのみをコールできます。public リモートアクションは global コンポーネントでは使用できません。一方、global スコープでは使用できます。スコープのエスカレーションはコンパイルエラーになります。または、実行時に解決される参照の場合は、実行時エラーになります。次の表では、これらの制限を詳細に説明します。
@RemoteAction のスコープ Visualforce Page 非グローバルコンポーネント グローバルコンポーネント iframe
グローバルリモートメソッド 使用可能 使用可能 使用可能 使用可能
公開リモートメソッド 使用可能 使用可能 エラー エラー
コンポーネント、<apex:include> タグまたは <apex:composition> タグによって間接的に含まれるマークアップを介してリモートアクションにアクセスする場合、リモートメソッドのスコープは最上位コンテナ (スコープのエスカレーションルールに準拠する必要のある包含階層の最上位項目) に継承されます。
最上位コンテナ
@RemoteAction のアクセス元 Visualforce Page 非グローバルコンポーネント グローバルコンポーネント iframe
グローバルコンポーネント 使用可能 使用可能 使用可能 使用可能
非グローバルコンポーネント 使用可能 使用可能 非グローバルコンポーネントが公開リモートメソッドを含まない場合にのみ使用可能。 非グローバルコンポーネントが公開リモートメソッドを含まない場合にのみ使用可能。
<apex:include> <apex:composition> 同じ名前空間内では使用可能。名前空間が異なる場合および含まれるページまたはその子階層に公開リモートメソッドが含まれる場合はエラー。 なし なし エラー

リモートメソッドと継承

@RemoteAction メソッドが検索またはコールされる場合、Visualforce ではページコントローラの継承階層を調べ、コントローラの上位階層のクラス内で @RemoteAction メソッドを検索します。

この機能を示す例を次に示します。次の Apex クラスでは 3 階層の継承階層を形成します。
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}
この Visualforce ページでは簡単な sayHello リモートアクションをコールします。
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>
リモートメソッドは ChildRemoteController クラス内には存在しません。代わりに、GrandparentRemoteController から継承されます。

インターフェースパラメータによるリモートメソッドの宣言

具象クラスに制限するのではなく、インターフェースパラメータと戻り値のデータ型を使用して @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}
JavaScript Remoting コールからインターフェースパラメータを宣言する @RemoteAction に送信されるオブジェクトは apexType 値を含む必要があります。この値は、具象クラスへの完全修飾パス、つまり、namespace[.BaseClass][.ContainingClass].ConcreteClass である必要があります。たとえば、上記のコントローラへの JavaScript Remoting コールを実行するには、次のコードを使用します。
1Visualforce.remoting.Manager.invokeAction(
2
3    '{!$RemoteAction.RemoteController.setMessage}',
4
5    {'apexType':'thenamespace.RemoteController.MyClass', 'myString':'Lumos!'}, 
6
7    handleResult
8
9);
組織内にクラス定義がある場合は、Remoting コールを単純化し、デフォルトの c 名前空間も使用できます。
1RemoteController.setMessage(
2
3    {'apexType':'c.RemoteController.MyClass', 'myString':'Lumos!'}, 
4
5    handleResult
6
7);

リモート応答の処理

リモートメソッドコールに対する応答は、リモートメソッドコールで提供されているコールバック関数によって非同期に処理されます。コールバック関数は、リモートコールの状況を表す event オブジェクト、およびリモート Apex メソッドで返される result オブジェクトをパラメータとして取得します。関数は返されるデータに基づいてページの情報およびユーザインターフェース要素を更新できます。

event オブジェクトは、リモートコールの成功または失敗に対応するうえで役立つ値を提供します。
  • event.status は、成功のときは true、エラーのときは false になります。
  • event.type は応答の種別です。成功したコールは rpc、リモートメソッドが例外を返した場合は exception のようになります。
  • event.message には、返されたエラーメッセージが含まれます。
  • event.where には、リモートメソッドにより生成された場合は、Apex スタック追跡が含まれます。

string または number など、result によって返される Apex プリミティブデータ型は対応する JavaScript に変換されます。返される Apex オブジェクトは JavaScript オブジェクトに変換され、コレクションは JavaScript 配列に変換されます。JavaScript は大文字と小文字を区別することに注意してください。そのため、idId、および ID は異なる項目であるとみなされます。

JavaScript リモートコールの一部として、Apex メソッド応答に同じオブジェクトに対する参照が含まれる場合、そのオブジェクトは返される JavaScript オブジェクトには複製されません。代わりに、表示される JavaScript オブジェクトには同じオブジェクトへの参照が含まれます。たとえば、同一オブジェクトを 2 回含むリストを返す Apex メソッドです。

デフォルトでは、リモートコールの応答は、30 秒以内に返される必要があります。これを超えると、コールはタイムアウトになります。要求の完了にこれ以上の時間を必要とする場合は、長いタイムアウトを 120 秒以内で設定します。

リモートコールの応答の最大サイズは 15 MB です。

JavaScript Remoting コードがこの制限を超える場合は、次のように対応できます。
  • 各要求の応答サイズを削減する。必要なデータのみを返します。
  • 大量データの取得を、小さなチャンクを返す複数の要求に分割する。
  • バッチ以外の要求を使用していることを確認する。Remoting 要求の設定ブロックで { buffer: false } と設定します。
  • バッチ要求の使用頻度を抑え、バッチサイズを削減する。

JavaScript Remoting を使用時に開発中の JavaScript コンソールを開いたままにします。JavaScript Remoting で発生するエラーや例外は、JavaScript コンソールが有効化されている場合はそれに記録され、有効化されていない場合は無視されます。

メモ

プログラミングエラーまたはその他の失敗により @RemoteAction メソッドで例外が発生すると、Apex スタック追跡がブラウザに返されます。JavaScript デバッガコンソールでスタック追跡を検査するか、応答コールバック関数のエラー処理でスタック追跡を使用します。次のコールバック関数では、例外がある場合にスタック追跡を表示します。
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 によりコントローラアクションメソッドをコールすることもできます。この 2 つの相違点の一部を次に示します。
  • <apex:actionFunction> タグ
    • ユーザが再表示ターゲットを指定できる
    • フォームを送信する
    • JavaScript の記述は不要
  • JavaScript Remoting:
    • ユーザがパラメータを渡すことができる
    • コールバックを提供する
    • 一部の JavaScript を記述する必要がある

通常、<apex:actionFunction> の方が使いやすく、必要なコードも少なくなります。一方、JavaScript では、より高度な柔軟性を提供できます。