dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

[Salesforce]関連リストのレコードを一括更新する方法〜その2〜

前回の記事に引き続いて、第2弾。

  1. javascriptだけで実装する
  2. Apex + Visualforce で実装する
  3. Apex Web Serviceを使って実装する

のうちの、今回は「2. Apex + Visualforce で実装する」です。

実装してみる

Visualforceページ、Apexを用意し、カスタムボタンからVisualforceにアクセスします。

Visualforce(MultiRecordProcess.page)

<apex:page standardController="MyObj__c" recordSetVar="myObjs" extensions="MultiRecordProcessController" action="{!execute}">
</apex:page>

ポイント

  • standardControllerには処理する対象のオブジェクトを指定する
  • extensionsactionはそれぞれ呼び出すApexクラスとメソッド名
  • recordSetVarはこのページ内でカスタムオブジェクトを使用するための変数名
    (らしい。どう使うのか、あまりよくわかっていない...)

Apex(MultiRecordProcessController.cls)

public class MultiRecordProcessController {

    List<MyObj__c> myObjList {get; set;}

    ApexPages.StandardSetController controller {get; set;}

    public MultiRecordProcessController(ApexPages.StandardSetController controller) {
        System.debug(LoggingLevel.INFO, controller);
        this.controller = controller;
    }

    public PageReference execute() {
        this.myObjList = (List<MyObj__c>) this.controller.getSelected();

        // オブジェクトMyObj__cのフィールドText__cを変更する
        for (MyObj__c myObj : this.myObjList) {
            System.debug(LoggingLevel.INFO, myObj);
            myObj.text__c = 'CHANGED';
        }
        update this.myObjList;

        String prevURL = '/' + System.currentPageReference().getParameters().get('retUrl');
        PageReference prevPage = new PageReference(prevURL); 
        return prevPage;
    }
}

ポイント

  • コンストラクタでApexPages.StandardSetControllerを受け取る
  • ApexPages.StandardSetController.getSelected()で、チェックを入れたレコードを取得できる
  • getSelected()で取得したレコードにはIdしかフィールド情報を持っていない
  • Urlパラメータを受け取るにはSystem.currentPageReference().getParameters().get([パラメータ名])を使う

カスタムボタンのjavascript

表示の種類:リストボタン  
動作:JavaScriptを実行  
内容のソース:OnClick JavaScript

で、こちらのコードを記述する。

window.location = 'apex/MultiRecordProcess?retUrl={!Account.Id}';

ポイント

  • Apexでの処理が終わった後に元のレコード詳細画面に戻れるよう、現在表示しているレコードのIdをretUrlというパラメータで渡す
    (今回は、取引先の詳細画面から実行することを想定)

が、ここで問題が...

この状態で実行してもうまくいかない。。。
どうやら、Apexの

this.myObjList = (List<MyObj__c>) this.controller.getSelected();

という箇所で選択したレコードが取得できず、空になってるようでした。

これについては、調べてみると以下の記事が。

http://abhithetechknight.blogspot.jp/2013/09/concept-of-standardsetcontroller-for.html

(記事引用)

but if we want to call that page where we are using StandardSetController by a JavaScript List View Button then we cant use this concept of StandardSetController, Because when are using Javascript button then method "getSelected()" stops working.

This is because when we use visualForce button to call our page then there is a direct call between page and the VF button so the above snippet works fine.

カスタムボタンのjavascriptからVisualforceを呼び出す形で
StandardSetController.getSelected()は使えないのか。

で、解決策もちゃんと書いてあった。
また、記事にあった方法じゃなくても(今回の場合だと)うまくいく方法があったのでそちらも書いておく。

解決策1(記事にあった方法)

カスタムボタンのjavascriptを次のようにする。

var records = {!GETRECORDIDS($ObjectType.MyObj__c)};
window.location = 'apex/MultiRecordProcess?id=' + records + 'retUrl={!Account.Id}';

カスタムボタンのjavascript内で「選択されたレコードのID」を先に取得し、パラメータとして渡すわけです。

そして、Apex側は次のように

// Urlパラメータのidを取得
String conId = ApexPages.currentPage().getParameters().get('id'); 

List<String> ids = new List<String>();
for(String str : conId.split(',')) {
    ids.add(str);
}

// クエリでレコードを取得
List<MyObj__c> myObjList = [SELECT Id FROM MyObj__c WHERE Id IN :ids];

カンマ区切りで渡されてきたIDを分割して、SOQLでレコードを取得します。
これだとたしかにいける。

解決策2

カスタムボタンの設定を次のように変更する。

動作:「JavaScriptを実行」以外
内容のソース:Visualforceページ
コンテンツ:作成したVisualforceページ

これだとダイレクトにVisualforceページに遷移するからか、うまくいきます。

おわりに

以下は、この実装方法についての個人的な感想。

よい点

  • ローカルでソースを管理する者としては、前回の方法1よりは良さそう

悪い点

  • レコードを編集したいだけなのにVisualforceページを1個用意するというところに違和感
  • 解決策1については、処理したいレコード数増えるとURLがすごい長くなってしまう
    (というか、リストのパラメータをカンマ区切りで渡すというやり方がイヤ)
  • 解決策2については、元のページにリダイレクトした後にjavascriptを実行できないので、アラートとかで結果を表示したりできない

(追記)

方法3 についてはこちら。

[Salesforce]関連リストのレコードを一括更新する方法〜その3〜 - dackdive's blog

リファレンス

カスタムオブジェクトのリストビューにVisualforce ページを表示するカスタムボタンを追加するには: Salesforce 奮闘記録

http://www.kokyakukanri.info/salesforce/blog/2010/10/post.html