プログラマ38の日記

主にプログラムメモです。

Salesforce: カスタムボタンのJavaScriptで注意すること

Salesforceでは、標準レイアウトにカスタムボタンを配置してアプリケーションを作成していきます。(Lightning Experience ではなくClassicを対象とした場合です)

 

自分がカスタムボタンの作成時に注意することのメモです。

  1. 環境依存の文字列はカスタム表示ラベルを使う
  2. オブジェクトの値を差し込む際は、改行や「"」や「'」が入る文字列は使わない
  3. カスタムWebServiceの戻り値ではJSON文字列を返却する
  4. 制御が複雑で、ネストが深くなる場合にはtry, catchをうまく使う

1. 環境依存の文字列はカスタム表示ラベルを使う

カスタムボタンでカスタム表示ラベル( {!$Label.Label1} など)は使えるので、環境依存する文字列、例えば、接続先のURLや、項目IDなどはカスタム表示ラベルにしておきます。※でも、項目IDについては、項目定義(FieldDefinition)のデュラブル ID(DurableId)から取得することをお奨めします。

2. オブジェクトの値を差し込む際は、改行や「"」や「'」が入る文字列は使わない

下記のようなId、日付項目、数値、チェックボックスは問題ないのですが、

( {!Opportunity.Id}、{!Opportunity.CloseDate}、{!Opportunity.Amount}、{!Opportunity.IsClosed} )
次のように、値に改行がはいったり、シングルクオテーション、ダブルクオテーションがはいる可能性がある項目は差し込むとJavaScriptがエラーとなる場合があります。
( {!Opportunity.Description} )

APIコール数が増えますが、カスタムWebServiceをコールしてApex内で処理するようにします。

3. カスタムWebServiceの戻り値ではJSON文字列を返却する

カスタムWebServiceでチェックをしたり、処理結果を戻したりする際には、JSON文字列で返却すると便利です。次のようなクラスを用意しておいて

public class ReturnSample {
  public Boolean IsSuccess;
  public Boolean IsWarning;
  public Boolean IsError;
  public String Message;
  public List<String> successIdList;
  public List<String> warningIdList;
  public List<String> errorIdList;
}

カスタムWebServiceで、上記インスタンスシリアライズして返却します。

ReturnSample retobj = new ReturnSample();
retobj.IsSuccess = true;
retobj.IsWarning = true;
retobj.IsError   = false;
retobj.Message   = '処理は完了しましたが、警告があります。XXXX';
retobj.successIdList = successlist;
retobj.warningIdList = null;
retobj.errorIdList   = warninglist;

return JSON.serialize(retobj);

そして、カスタムボタンではJSON文字列をデシリアライズして使います。

var retjson = sforce.apex.execute('SampleWebService','samplemethod', { arg1 : '{!Case.Id}' } ); 
var retobj  = JSON.parse(retjson);

多少込み入った処理を実装する場合でも、必要な情報は返却できると思います。

4. 制御が複雑で、ネストが深くなる場合にはtry, catchをうまく使う

カスタムボタンである程度ロジックを組む場合があると思います。 特にやっかいなのが、確認メッセージを出して"OK"なら次へ、"キャンセル"の場合は中断するという制御です。

この制御をifを使って実装すると、ネストが確認メッセージ分深くなっていきます。そこで、次のようにtry, catchを使ってジャンプさせてしまうのはどうでしょうか。


try{
  var retjson = sforce.apex.execute('SampleWebService','samplemethod', 
{ arg1 : '{!Case.Id}' } ); 
  var retobj  = JSON.parse(retjson);

  if( retobj.IsSuccess == true ) {
    if( retobj.IsWarning == true ){
      if( confirm('次の警告が発生しています。処理を続けますか? ' + retobj.Message) == false){
         throw { quietclose : true };
      }

      var retjson2 = sforce.apex.execute('SampleWebService','samplemethod2', 
{ arg1 : retobj.successIdList ,arg2 : retobj.warningIdList } ); 
      var retobj2  = JSON.parse(retjson2);

      if( retobj2.IsSuccess == true ){
        if( confirm('次の警告が発生しています。処理を続けますか? ' + retobj2.Message) == false){
           throw { quietclose : true };
        }

        var retjson3 = sforce.apex.execute('SampleWebService','samplemethod3',    { arg1 : retobj2.successIdList ,arg2 : retobj2.warningIdList } ); 
        var retobj3  = JSON.parse(retjson2);
        ・・・・・・・・・

      } else {
        throw retobj2.Message;
      }

    }
  } else {
    throw retobj.Message;
  }

} catch( ex ){
  if( ex.quietclose == true ){
    //何もせず終了する
  } else {
    alert( ex );
  }
}

ポイントは、メッセージ表示はcatchにまかせている点、catchにquietcloseプロパティをtrueにして投げると、何も表示せずに終わるようにしている点です。

上記のサンプルでも結構わかりずらいですが、これを全てifのブロックで実現した場合、ネストが相当深くなりメンテナンスが大変になっていきます。

 

最後に

カスタムボタンや、メールテンプレートではカスタム表示ラベルが使えるのに、差込項目として選べないんですよね。
本番にリリースするたびに、カスタムボタンなメールテンプレートの文字列を本番用に変更しているプロジェクトがあると大変そうだなと思います。カスタム表示ラベルではなく直に環境依存の文字列を書いていると予想できますが、一度決めた運用なので変更しずらいのだと思います。

 

後、この慣れ親しんだカスタムボタンもLightning Experienceを採用して使わなくなる日も近いのでしょうね。。 ガバナ制限を回避のため、カスタムボタンの中でカスタムWebServiceを細かく呼び出すような設計をすることがありますが、そういった部分がLightning Experienceでどうなるのか把握できていません。なかなかLightning Experienceへ切り替えができないでいます。。