2020年10月11日日曜日

サービス実行後に実行するプログラムを登録する

今回のテーマは、タイトルは違いますが前回のエントリと同じです。

前回のエントリでは、REST API の戻り値が複数ある場合に HCL Domino Volt のページ上にある表へセットする方法について紹介しました。REST API が戻した JSON の値を Volt のフォーム上の表へセットするために、フォームのイベントへ「サービス構成」を行うものです。

前回のおさらいをすると、REST API が返す JSON は次に示すような構造でした。

{
  "results": [
    {
      "formatted_address": "値(住所)",
    },
    ・・・
  ]
}

この JSON から "results" という配列にあるオブジェクトから "formatted_address" というキーの値を取り出しました。"results" は配列なので、複数のオブジェクトが存在する場合があります。

今回扱う JSON は次に示すとおり、配列の中にあるオブジェクトの中にさらに配列がある「入れ子」構造です。

{
   "Feature": [
      {
         "Property": {
            "WeatherList": {
               "Weather": [
                  {
                     "Type": "observation",
                     "Date": "202009212320",
                     "Rainfall": 0
                  },
                  ・・・
               ]
            }
         }
      }
   ]
}


ただし今回扱いたかった JSONでは、上位の配列 "Feature" にはオブジェクトが1つだけ存在し、そのオブジェクトの中の配列 "Weather" は複数のオブジェクトを持つ、という約束があるようでした。
下位の配列のオブジェクトにある Type, Date, Rainfall の値を Volt の表で表示したいのです。


REST API が返す JSON に配列の入れ子(配列の中に配列)が存在し、かつ最下層の配列から値を取得したい場合、現状の Volt では表の中に表を作るなどして、入れ子の階層をレスポンスの配列階層と合わせなければ「サービス構成」による構成中に「割り当てが無効です。ソースとターゲットは祖先と同じ数のリスト(または表)を持つ必要があります。」(下図赤枠)と表示され、構成できません。


そこで試してみたところ、表の中に表を作ることは可能でしたので、なんとなく入れ子の表を作ってみました。

下位の表には列として3つの単一行エントリを配置しています。


するとサービス構成で割り当てすることができました。 ただし、構成した後にプレビューしてみると、入れ子構造の表を表示することができません。


現状では JSON で入れ子の配列の値を取得できても、それを Volt の表で表現することができないようでした。


このことをサポートへ報告したところ「入れ子にされた表の表示を現状サポートしていない」(※2020年9月の話です)とのこと。

食い下がってなんとか表示する方法について聞いてみたところ、奥の手のような回避策をご提案いただきました。

今回はその回避策をご紹介します。


実は、「サービス構成」で入れ子の表(にあるフィールド)へ割り当てた場合、表示はできませんでしたが、値は割り当てたとおりにセットされていたのです。


この回避策は「サービス構成」によって入れ子の表に値がセットされていることを前提としていますが、「サービス構成」で作成したサービスが終了したタイミングで、次のようなプログラムを実行する、というものでした。

  1. 「サービス構成」で取得できた値を表から取り出しながら
  2. <table>...</table>等のHTMLタグを付加して加工した文字列を作成
  3. 作成した文字列をHTMLフィールドへセット


まずは「サービス構成」で定義した処理の終了後に実行するプログラムです。

var srv = form.getServiceConfiguration( "SC_ServiceConfig0" );
srv.connectEvent( "onCallFinished", function( success ) {
  if ( success ) {
    var s = app.getSharedData().printTable( BO.F_Table1 );
    form.getPage( "P_NewPage1" ).F_HTMLArea1.setContent( s );
  }
});

ここで "SC_ServiceConfig0" は、onShow イベントで「サービス構成」を設定する際に「4.詳細」タブに指定したIDです。ここではIDにデフォルト値として設定されていたものを使っています


このサービスに onCallFinished というイベントを設定しています。onCallFinished を設定することで、サービス構成で設定した処理の終了時に任意の処理を実行することが可能になります。

サービス構成で設定した処理が正常に終了した場合(if (success) の部分)に実行するプログラムとして、printTable を指定しています。printTable の頭についている "app.getSharedData()." ですが、これはフォーム上にある「カスタムJavaScript」を定義したり呼び出す場合に使います。ここで呼び出しているプログラムが次に示すプログラム printTable です。このプログラムを記述するために app.getSharedData() を使っています。

プログラムの引数 "BO.F_Table1" ですが、F_Table1 は入れ子の表の上位階層にある表のIDで、その頭についている BO は Business Object の略のようです。

プログラム printTable を実行すると HTML の文字列を返します。

その HTML 文字列をページ( "P_NewPage1" )にある HTML エリア( "F_HTMLArea1" )へセットします。※HTML エリアとはパレットの「特殊」にある 「HTML」を指します(下図)


以上のプログラムと次に示すプログラムを、フォームの onLoad イベントに記述しています。


以下は、表から値を取り出しながら HTML を生成するプログラムです。入れ子の表に対応するため再帰的に呼び出し可能な関数になっています。

app.getSharedData().printTable = function( table ) {
  var s = "<table width='90%' cellpadding='0' cellspacing='0'>";
  for(var i = 0; i < table.getLength(); i++) {
    var row = table.get( i );
    s += "<tr>";
    var ol = row.getChildren();
    for( var j = 0; j < ol.getLength(); j++ ) {
      var f = ol.get(j);
      if( f.getType() === "BusinessObjectList" ) {
        var innerS = app.getSharedData().printTable( f );
        s += innerS;
      } else {
        s += "<td>";
        var v = f.getValue();
        s += v;
      }
      s += "</td>";
    }
    s += "</tr>";
  }
  s += "</table>";
  return s;
}

以上のような奥の手を使うことで実現した結果が下図にある7行3列の(Volt アプリなのに Volt アプリっぽくない)表です。


今回のように REST API が返す値を加工して表示したい場合に使えそうです。

ノーコード/ローコードのツールでここまでやるのもどうかと思いますが、JavaScriptで作りこみたい場合にこちらのドキュメントが参考になると思います。

0 件のコメント:

コメントを投稿