1のスクリプトだと動作するが、2つのスクリプトを実行すると動作しない

背景・実現したいこと

こんにちは。
以下2つのアプリ間で[社員マスタ]を更新した時に[アプリA]のルックアップ を更新したいと思い、以下コードを作成しました。

使用したアプリ(うまくいった)
・社員マスタ(updateLookup_A.js)
・アプリA

この段階ではエラーは出ずに思ったとおりの動作をしてくれました。

 

エラー情報

うまく動作したのでアプリBに対しても同様の処理をしたいと思い [updateLookup_2.js] を作成しました。

使用したアプリ(エラーが出た)
・社員マスタ(updateLookup_A.js、updateLookup_B.js)
・アプリA
・アプリB

しかし実行してみると「Uncaught TypeError: Cannot read property ‘姓名’ of undefined」とエラーが出てしまいます。しかし作成した2つのJSファイルのどちらか片方を削除すると動作します。

変数 paramGet の名前空間やスコープに問題があるのでしょうか?

どなたかエラーの原因を教えていただけませんでしょうか。
よろしくお願いいたします。

 

利用したソースコード

updateLookup_A.js

(function() {
'use strict';

function createPutRecords(records,fieldName) {
const putRecords = [];
for (let i = 0; i < records.length; i++){
const record = records[i];
putRecords[i] = {
id: record.$id.value,
record: {
報告者: {
value: record['報告者'].value
}
}
};
}
return putRecords;
}

kintone.events.on('app.record.edit.submit.success', function(event) {
const record = event.record;

// レコードの一括取得
const paramGet = {
'app': 6,
'query': '報告者 = "' + record['姓名'].value + '"'
};
console.log(paramGet);
return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', paramGet)
.then(function(resp){
const records = resp.records;
console.log(records);
const paramPut = {
'app': 6,
'records': createPutRecords(records)
};
console.log(paramPut.records);
return kintone.api(kintone.api.url('/k/v1/records', true), 'PUT', paramPut);
});
});
})(); 

updateLookup_B.js

(function() {
'use strict';

function createPutRecords(records) {
const putRecords = [];
for (let i = 0; i < records.length; i++){
const record = records[i];
putRecords[i] = {
id: record.$id.value,
record: {
受講者: {
value: record['受講者'].value
}
}
};
}
return putRecords;
}

kintone.events.on('app.record.edit.submit.success', function(event) {
const record = event.record;

// レコードの一括取得
const paramGet = {
'app': 19,
'query': '受講者 = "' + record['姓名'].value + '"'
};
console.log(paramGet);
return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', paramGet)
.then(function(resp){
const records = resp.records;
console.log(records);
const paramPut = {
'app': 19,
'records': createPutRecords(records)
};
console.log(paramPut.records);
return kintone.api(kintone.api.url('/k/v1/records', true), 'PUT', paramPut);
});
});
})();

まず何故「Uncaught TypeError: Cannot read property ‘姓名’ of undefined」のエラーが出ているのかデバッグしてみましょう。

動かない?そんな時はデバッグをしてみよう!入門編

event 変数の中身が壊れているのがわかると思います。

event の中身を壊した犯人は、直前に実行した updateLookup_A.js です。

イベント終了時に event 情報を返すべきところ、REST API の応答情報をそのまま返していますので、次の updateLookup_B.js に event 情報の代わりにREST API の応答情報が渡されてしまします。

一つのイベントに、複数のイベント処理がある場合、 event 情報が順番に引き継がれていきます。

イベント終了時は、必ず return event; するようにしましょう。

updateLookup_A.js 、 updateLookup_B.jsが単独で動く分には、問題ないのですが、後続で実行される他の JavaScript やプラグインに影響します。

 

ご返信いただきありがとうございます。
Promiseの記述ミス?スコープ?など解決の糸口がつかめない状況でしたので、大変助かりました。
コードを下記のように修正することでエラーが解決しました。

イベント処理の記述方法に「下記の Promise 対応イベントのハンドラー内で kintone.Promiseオブジェクト※を return すると、非同期処理の完了を待って次の処理を開始します。」という記述があります。

今回のエラーの原因ですが

・event(=kintone.Promiseオブジェクト)をreturnしていなかった
・そのためイベントの処理を待たず非同期で意図しない順番で処理が実行された
・その結果エラー(event変数の中身が壊れている)が発生した

という認識であっておりますでしょうか。

 

(function () {
'use strict';

function createPutRecords(records, fieldName) {
const putRecords = [];
for (let i = 0; i < records.length; i++) {
const record = records[i];
putRecords[i] = {
id: record.$id.value,
record: {
報告者: {
value: record['報告者'].value
}
}
};
}
return putRecords;
}

kintone.events.on('app.record.edit.submit.success', function (event) {
const record = event.record;

// レコードの一括取得
const paramGet = {
'app': 6,
'query': '報告者 = "' + record['姓名'].value + '"'
};
console.log(paramGet);
return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', paramGet)
.then(function (resp) {
const records = resp.records;
console.log(records);
const paramPut = {
'app': 6,
'records': createPutRecords(records)
};
console.log(paramPut.records);
return kintone.api(kintone.api.url('/k/v1/records', true), 'PUT', paramPut);
})
.then(function () {
return event;
});
});
})();

今回は、下記の通りだと思います。

・eventをreturnせずに、REST API (非同期)の完了を待って、REST API の返り値(kintone.Promiseオブジェクト)を return している

・順番に updateLookup_B.jsが実行されるが、event変数の中身が壊れているので、エラーが発生

デバッガーで、処理の順番を確認してみてください。

 

 

ご返信ありがとうございます!
エラーの原因はeventをreturnしていなくてevent変数が壊れていることであると理解しました。

そこで疑問なのですが「updateLookup_A.js」「 updateLookup_B.js」はどちらも即時関数で記述しています。「updateLookup_A.js」でevent変数の中身が壊れたとして「updateLookup_B.js」のevent変数にも影響してくるのはなぜでしょうか。

お行儀は良くないコードだとは思いますがスコープは問題ない気がします。バンドルした際にエラーが出るコードになってしまうのでしょうか。

何度も質問すみません。

イベント処理のしくみで、event を順番に引き継ぎます。

app.record.edit.submit で、event.record を各イベント処理で変更する場合のほうがわかりやすいと思います。

各イベント処理で、event.record を変更する場合、event を各イベント処理で引き継がないと、途中の変更内容が失われます。

app.record.edit.submit.success も同じしくみで動きます。

ご返信ありがとうございます!
ようやくreturn eventの挙動に理解することが出来ました。
丁寧にご指導いただきありがとうございました。

私も自分なりに調べてみたところ、以下のことがわかり理解を深めることが出来ました。

・return eventをreturn Promise(オブジェクト)とするとエラーが発生する
→eventの内容がreturn Promiseの内容に書き変わってしまいエラーになる
参考:kintoneカスタマイズのつまづきポイント

・kintoneは最後にイベントハンドラが返した event オブジェクトを処理している
参考:Return Eventの仕様? 同じイベントで複数のことを実行できません。。どなたかお助けを。。