イベントの振り分けと false による中止条件
$p.events に関数を置くだけでは、その戻り値が処理を止めるかは決まりません。_event.js が関数を探して結果をまとめ、_form.js や _ajax.js などの呼び出し元が false を見て中止するかを決めます。
DOM の change を扱う 項目イベントと、ここで扱う $p.events の名前による呼び出しは別です。
eventArgs は引数を包むだけ
eventArgs(url, methodType, data, $control, _async, ret, json) は、新しいオブジェクトに7つの値を入れます。イベントを登録・発火する関数ではありません(引数の組み立て)。
| プロパティ | 内容と確認点 |
|---|---|
url | 処理先の URL。send の初期段階では null |
methodType | get・post などのメソッド |
data | 渡されたデータへの参照。初期段階や GET では null の場合がある |
$control | 操作元の jQuery オブジェクト。呼び出し経路によってはない |
async | 非同期指定。ただしイベントの位置によっては既定値の補完前 |
ret | 呼び出し元の結果値。通信完了前と後を区別する |
json | 成功応答など。常に命令配列が入るわけではない |
オブジェクトや jQuery 要素をコピーする処理はありません。args.data を変えると、呼び出し元と同じオブジェクトを変えることになります(eventArgs)。
execEvents は3段階で呼ぶ
例えば event が before_send、コントロールが id="Update" data-action="Update" なら、次の順に呼び出します(振り分け)。
$p.events.before_send$p.events.before_send_Update(ID)- ID と data-action が異なる場合だけ、アクション名のイベント
文字列は大文字小文字を含めて、そのまま連結します。data-action がない場合でも ID と異なると判定され、末尾が _undefined の名前を探す経路があります。$control がない引数では、共通イベントだけです。
図を読み込み中…
共通イベントの false でも後続ハンドラは実行する
execEvents の内部では、各ハンドラが 厳密に false を返したときだけその結果を false にします。未登録や undefined の戻り値は true 扱いです。
ID・アクション別の呼び出しは exec(名前) && result の順なので、既に result が false でも exec を実行します。すべての名前を呼んだうえで、一つでも false なら最終結果が false です。共通ハンドラの false は、後続ハンドラを呼ばない指定ではありません(集約の実装)。
中止できる位置は呼び出し元で決まる
| イベント | false による通常処理の中止 | 条件・位置 |
|---|---|---|
before_setData | できる | send 内、バッファ取得前 |
after_setData | できる | send 内、バッファ取得後。ただし必須項目の収集前 |
before_validate | できる | send 内、validate クラスがある場合 |
after_validate | できる | send 内、検証成功後 |
before_send | できる | ajax 内、CAPTCHA 準備後・確認ダイアログ前 |
after_send | できない | 呼び出し元が結果を使わない。通信完了の合図でもない |
before_set・after_set | できない | dispatch の前後。戻り値を中止条件に使わない |
ajax_before_send などの ajax_* | できない | execEvents を呼ぶが戻り値を中止条件に使わない |
根拠は イベントのラッパー、send、ajax、dispatchです。controlAutoPostBack は send を経由しないため、最初の4つの send 内イベントは呼びません(別の送信経路)。
after_setData という名前でも、DOM の全項目の収集が終わった位置ではありません。setMustData は send の後段です。
更新ボタンだけを同期的に確認する例
次のブラウザ側のスクリプトを新規・編集画面へ配置します。data-action="Update" の操作で、確認をキャンセルしたら通信を止めます。通常の更新ボタンが対象で、検証用レコードで確認してください。
$p.events.before_send_Update = function (args) {
return window.confirm('この内容で更新しますか?');
};キャンセル時には、この before_send の中止判定で $p.ajax が false を返します。既存のハンドラがある場合は 複数処理の登録で追加します。本体の data-confirm による確認がある操作では、それも後に実行されるため、二重確認の有無を確かめます(確認の順序)。
非同期の false では中止しない
例えば async function () { return false; } の即時の戻り値は Promise です。execEvents は Promise の完了を待たず、=== false を判定するため、この書き方では中止できません(厳密な判定)。
非同期の事前確認をするなら、最初の処理では同期的に false を返していったん中止し、確認完了後に明示的に再実行する設計が必要です。そのときは再確認のループや二重送信を防ぐ状態管理も用意します。ここでは、同期待機型の確認例に限定しています。
名前の振り分けだけを保存せずに試す
次はブラウザコンソール用です。DOM に接続していないボタンを用い、独自のイベント名で3つのハンドラを試します。send や ajax は呼びません。
(function () {
const names = ['manualEventLab', 'manualEventLab_TestButton', 'manualEventLab_Update'];
const previous = names.map(function (name) { return $p.events[name]; });
const order = [];
try {
$p.events[names[0]] = function () { order.push('共通'); return false; };
$p.events[names[1]] = function () { order.push('ID'); };
$p.events[names[2]] = function () { order.push('action'); };
const $button = $('<button/>').attr({ id: 'TestButton', 'data-action': 'Update' });
const result = $p.execEvents(names[0], $p.eventArgs('/test', 'post', {}, $button, true));
console.log(order); // 共通、ID、action の順
console.log(result); // false
} finally {
names.forEach(function (name, index) {
if (previous[index] === undefined) delete $p.events[name];
else $p.events[name] = previous[index];
});
}
})();この例と、false の集約・同一 ID/action の省略・Promise の扱いは、本体 JavaScript で確認しています。実機の更新操作は未検証です。