kintone.Promiseとは
kintone Javascriptカスタマイズでレコード保存前などのkintoneのイベント実行時処理内にkintone.apiやkintone.proxyといった非同期処理を扱うと先にイベント実行処理が完了してしまい利用することができませんでした。
例えば、「レコード保存時に別アプリのレコード情報を取得して、指定のフィールドにセットして保存」といった処理ができず、XHRで同期処理をするか保存後のレコード詳細画面表示時に実装をするといった方法しかありませんでした。
XHRで同期処理をすることで簡単に解決はできますが、Firefoxでは非推奨で今後サポートをしない可能性があるので弊社では基本利用せずにレコード詳細画面時に実行する方法で実装していました。
そこで登場したのが2015年7月版アップデートの目玉機能のひとつ kintone.Promise です。
kintone.Promiseを利用することでイベント実行時処理の中でkintone.apiやkintone.proxyを扱うことができるようになります。
Promise内で複数回kintone.apiを実行してみる
kintone.Promiseの利用方法は developer networkにサンプルコードが書かれています。
このサンプルはkintone.Promise内で他アプリのレコード情報を取得し、取得した値をフィールドにいれるという例でPromise内でkintone.apiを1回実行していますが、自分自身がPromiseの理解度が低いということもあり、kintone.Promise内で複数回kintone.apiを実行した時の実装方法に悩んだため、共有がてらこちらで公開をしたいと思います。
今回はレコード保存時に別アプリにレコードを作成し(POST)、作成したレコードからアプリコード付きのレコード番号を取得(GET)してフィールドにセットをするというシーンを想定します。
※余談ですが、なぜレコード作成時に取得したレコードIDじゃないとだめなのかというとアプリコード付き、レコード番号を別アプリのフィールドにセットすると自動的にリンクが付き該当レコードにアクセスができるというメリットがあるためです。
まずkintone.Promiseを実行するアプリ「Promiseテスト」を作成します。シンプルに以下の3フィールドを作成します。
フィールド名 | フィールドコード | 利用目的 |
---|---|---|
連携先アプリのレコード番号 | 連携先アプリのレコード番号 | 別アプリに作成されたレコード番号を格納 |
連携項目1 | 連携項目1 | 別アプリにコピーするフィールド |
連携項目2 | 連携項目2 | 別アプリにコピーするフィールド |
フォーム設定画面ではこんな感じです。
続いて「Promiseテスト」アプリからレコードを作成するアプリ「コピー先アプリ」を作成します。こちらもシンプルに2フィールドだけ作成します。
フィールド名 | フィールドコード | 利用目的 |
---|---|---|
連携項目1 | 連携項目1 | 別アプリにコピーするフィールド |
連携項目2 | 連携項目2 | 別アプリにコピーするフィールド |
続いて、「コピー先アプリ」アプリ管理画面の「詳細設定」から「高度な設定」を選び、アプリコードを登録します。
これを設定するとレコード番号が「アプリコード – 連番」という採番になります。ちなみにアプリコードは一度設定すると変更できないのでご注意を。
アプリの準備ができたら「Promiseテスト」アプリにjavascriptで以下のような仕様を実装します。
1.レコード保存時に「連携項目1」と「連携項目2」の値を「コピー先アプリ」の「連携項目1」と
「連携項目2」の値にセットしてレコードを登録する。
2.登録後のレスポンスで返されるレコードIDをキーにして「コピー先アプリ」からレコードを検索し、
「レコード番号」フィールドの値を取得する。
3.取得した「レコード番号」フィールド値を「連携先アプリのレコード番号」フィールドにセットする。
コードで書くとこんな感じです。
"use strict"; (function() { // レコード登録画面の保存時 kintone.events.on('app.record.create.submit', function(event) { var record = event.record; return new kintone.Promise(function(resolve,reject){ kintone.api("/k/v1/record","POST", //コピー先アプリ { app : 113, //コピー先アプリのアプリID record : { 連携項目1 : { value : record['連携項目1']['value'] }, 連携項目2 : { value : record['連携項目2']['value'] } } }, function(post_resp) { //callback kintone.api('/k/v1/record','GET', { app : 113, //コピー元アプリのアプリID id : post_resp['id'] //作成したレコードのレコードID },function(get_resp){ resolve(get_resp); //thenへ },function(get_error){ reject(get_error); //エラーはcatchへ }); }, function(post_error) { reject(post_error); //エラーはcatchへ }); }).then(function(resp){ record['連携先アプリのレコード番号']['value'] = resp['record']['レコード番号']['value']; //レコード番号を「連携先アプリのレコード番号」フィールドにセット return event; }).catch(function(error){ event.error = 'エラーが発生しました。'; return event; }); }); })();
このjavascriptを「Promiseテスト」アプリに登録し、新規にレコード登録します。
保存後にコピー元アプリに作成したレコード番号が登録されていることが確認できます。そしてアプリコード付きなのでアンカーが貼られクリックすると該当レコードの詳細画面にアクセスができます。
「連携先アプリのレコード番号」フィールドに値をセットする場合、以下の作成した17行目以降の作成したレコードのレコード番号を取得した後のコールバック内で
record['連携先アプリのレコード番号']['value'] = get_resp['record']['レコード番号']['value'];
と書いて return event すれば行けそうな気がしますが
returnした関数のなかで設定しないとフィールドに値がセットされないため、これでは「連携先アプリのレコード番号」フィールドに値がセットされて保存されません。
function(post_resp) { //callback kintone.api('/k/v1/record','GET', { app : 113, //コピー元アプリのアプリID id : post_resp['id'] //作成したレコードのレコードID },function(get_resp){ resolve(get_resp); //thenへ //ここに //record['連携先アプリのレコード番号']['value'] = get_resp['record']['レコード番号']['value']; //書いちゃだめ? },function(get_error){ reject(get_error); //エラーはcatchへ }); }, function(post_error) { reject(post_error); //エラーはcatchへ });
return は
return new kintone.Promise(function(resolve,reject){ });
で行いますので、kintone.Promiseのthen内でフィールド値をセットしなければいけません。そして、このthenに値を渡すために23行目で resolve に取得したオブジェクトをセットしています。
また、エラーはrejectに値をセットするとkintone.Promiseのcatchに渡りますのでその中でエラー制御を書けばOKです。
最後に余談ですがPromise対応以前はこんな感じでもいけるんじゃないかと思いがちですが、kintone.apiの処理が終わる前にイベント処理が終わります・・・・
"use strict"; (function() { // レコード登録画面の保存時 kintone.events.on('app.record.create.submit', function(event) { var record = event.record; kintone.api("/k/v1/record","POST", //コピー先アプリ { app : 113, //コピー先アプリのアプリID record : { 連携項目1 : { value : record['連携項目1']['value'] }, 連携項目2 : { value : record['連携項目2']['value'] } } }, function(post_resp) { //callback kintone.api('/k/v1/record','GET', { app : 113, //コピー元アプリのアプリID id : post_resp['id'] //作成したレコードのレコードID },function(get_resp){ //callback record['連携先アプリのレコード番号']['value'] = resp['record']['レコード番号']['value']; //レコード番号を「連携先アプリのレコード番号」フィールドにセット return event; },function(get_error){ event.error = 'エラーが発生しました。'; return event; }); }, function(post_error) { event.error = 'エラーが発生しました。'; return event; }); })();