dispatch の実装サンプル
dispatch の仕組みで説明した命令を、目的別に組み合わせます。サーバースクリプトは応答を作り、ブラウザ側のスクリプトがその命令を実行します。同じ JavaScript でも、配置する場所が違います。
本体 1.5.8.1 の JavaScript を DOM 環境で動かして命令の挙動を確認したサンプルです。プリザンター実機での動作確認結果ではありません。サーバーとの連携例は、タイトル項目がある検証用テーブルの通常の編集画面で試してください。
画面の値と送信バッファを明示的に揃える
SetValue で画面を更新し、SetFormData で応答処理に渡された送信バッファへ同じ値を登録します。通常の単一選択の Set が発火させる change に依存せず、反映先を明示する組み合わせです。
サーバースクリプトの実行条件を「画面表示の前」にします。既存レコードの編集画面だけを対象にするため、コードでも条件を絞ります。
if (context.Controller === 'items' && context.Action === 'edit') {
const id = context.ReferenceType + '_Title';
const value = '応答で設定したタイトル';
context.AddResponse('SetValue', '#' + id, value);
context.AddResponse('SetFormData', id, value);
}編集画面を開くと、タイトル入力欄と $p.data.MainForm の該当キーを確認できます。
const $title = $p.getControl('Title');
console.log($title.val());
console.log($p.getData($title)[$title.attr('id')]);この応答だけで DB のタイトルを保存するわけではありません。保存値と比較するには、更新操作と再読み込みが必要です。別の応答に ClearFormData やフィールドの差し替えがあれば、その後の値も調べます。初回表示時の応答に渡されるデータは #MainForm のバッファです(初回の呼び出し)。条件名と URL の関係は contextを参照してください。
非表示のまま値を変えたい場合
SetValue は値の設定後に hideField も呼びます。Options を省略すると Hide が true ではないため、対象フィールドの hidden クラスを外します。非表示を維持する場合は、上の SetValue の行を次に置き換えます。
context.AddResponse(
'SetValue',
'#' + id,
value,
JSON.stringify({ Hide: true })
);id と value は上のサーバーコードで定義した変数です。対象は入力要素、表示を制御する要素はその ID に Field を付けたものです(SetValue、hideField)。
サーバーの結果を独自のブラウザ関数へ渡す
サーバーで作った状態を SetMemory に積み、直後の Invoke で表示します。自作のサンプルでは JSON 文字列で受け渡しし、ブラウザ側で解析します。
ブラウザ側のスクリプトを新規・編集画面に配置します。関数の定義を on_editor_load の中に入れず、トップレベルに置きます。初回の応答から呼ばれる時点で関数が必要だからです。
$p.manualRenderHint = function (json) {
const request = JSON.parse(json);
const state = JSON.parse($p.manualDispatchState);
const $field = $p.getField('Title');
if (!$field || $field.length !== 1) return;
let $hint = $('#ManualDispatchHint');
if ($hint.length === 0) {
$hint = $('<div/>').attr('id', 'ManualDispatchHint').insertAfter($field);
}
$hint.text(request.text + ' / ' + state.stage);
};サーバースクリプトの実行条件を「画面表示の前」にして、次を配置します。最初のサンプルとは別に試せます。
if (context.Controller === 'items' && context.Action === 'edit') {
context.AddResponse(
'SetMemory',
'manualDispatchState',
JSON.stringify({ stage: '確認待ち' })
);
context.AddResponse(
'Invoke',
'manualRenderHint',
JSON.stringify({ text: 'サーバーから受け取った状態' })
);
}タイトルの下に サーバーから受け取った状態 / 確認待ち と表示します。SetMemory を後ろへ移すと、関数はその応答の新しい状態をまだ読めません。Invoke の対象は $p の直接のキーです。manualRenderHint を指定し、$p.manualRenderHint という文字列は指定しません(命令の実装、Invoke)。
表示には .text() を使うので、受け取った文字列を HTML として挿入しません。この関数は同期処理です。Invoke は Promise の完了を待たないため、後続命令が非同期処理の結果に依存する構成には使えません。
フィールド差し替え後に説明を付け直す
タイトルのフィールド内に独自の説明を置く例です。応答でフィールドが置き換わると、その中の説明も失われるため、現在の DOM を取得して作り直します。Invoke は UI の再適用より前に実行されます。再適用後に処理したい場合は after_set を使います。
以下はブラウザ側のスクリプトです。初回表示には on_editor_load、URL を伴う応答には after_set を使います。
$p.manualRebuildTitleNote = function () {
const $field = $p.getField('Title');
if (!$field || $field.length !== 1) return;
if ($field.find('.manual-title-note').length === 0) {
$('<small/>')
.addClass('manual-title-note')
.text('タイトルは内容が分かる名前を入力してください。')
.appendTo($field);
}
};
$p.events.on_editor_load = function () {
$p.manualRebuildTitleNote();
};
$p.events.after_set = function (args) {
const htmlMethods = ['Html', 'ReplaceAll', 'Append', 'Prepend', 'After', 'Before'];
if (args.json.some(function (command) {
return htmlMethods.indexOf(command.Method) !== -1;
})) {
$p.manualRebuildTitleNote();
}
};このコードを繰り返し呼んでも、同じフィールド内に説明を重複追加しません。初回の setByJson は URL が渡されないため after_set が呼ばれず、初回用のイベントが必要です。応答時には全命令・apply・applyValidator の後で after_set が呼ばれます(実行順、編集画面の初回イベント)。
既存のイベントへそのまま代入すると、その処理を上書きします。既存処理があるテーブルでは 複数処理の登録のヘルパーを使って、この2つの処理を追加してください。
保存せずに命令を比較する実験用フォーム
通常の編集画面の開発者ツールで、次のブラウザ用コードを実行します。専用のフォームと送信バッファを作り、レコードの入力欄とは別に動きを比べます。送信を防ぐため、フォームの submit を止めます。
if ($('#ManualDispatchForm').length === 0) {
$('<form id="ManualDispatchForm">' +
'<div id="ManualDispatchTextField">' +
'<input id="ManualDispatchText" type="text" value="初期値"></div>' +
'<select id="ManualDispatchChoice">' +
'<option value="a">A</option><option value="b">B</option></select>' +
'</form>')
.on('submit', function (event) { event.preventDefault(); })
.appendTo('body');
}
$p.manualDispatchLab = function (commands) {
const data = $p.getData($('#ManualDispatchText'));
$p.setByJson(undefined, 'post', data, $('#ManualDispatchText'), true, commands);
return data;
};URL を undefined にしているため、before_set と after_set は呼ばれません。true はイベント引数用の値であり、この呼び出しを非同期にする指定ではありません。HTML 更新の命令を加えると本体の UI 再適用も呼ばれるため、ここでは値とバッファの命令だけを試します。
SetValue だけではバッファに入らない
delete $p.getData($('#ManualDispatchText')).ManualDispatchText;
const result = $p.manualDispatchLab([
{ Method: 'SetValue', Target: '#ManualDispatchText', Value: '画面だけ' }
]);
console.log($('#ManualDispatchText').val()); // 画面だけ
console.log(result.ManualDispatchText); // undefined
$p.manualDispatchLab([
{ Method: 'SetFormData', Target: 'ManualDispatchText', Value: '送信だけ' }
]);
console.log($('#ManualDispatchText').val()); // 画面だけ
console.log(result.ManualDispatchText); // 送信だけresult はバッファそのものの参照なので、次の命令による変更も読み取れます。
SetData は現在の DOM の値を登録する
const result = $p.manualDispatchLab([
{ Method: 'SetData', Target: '#ManualDispatchText' }
]);
console.log(result.ManualDispatchText); // 画面だけ
$p.manualDispatchLab([
{ Method: 'ClearFormData', Target: 'ManualDispatchText' }
]);
console.log(result.ManualDispatchText); // undefined
console.log($('#ManualDispatchText').val()); // 画面だけ前の実験の続きで実行します。ClearFormData はキーを消しますが入力欄を消しません。このあと SetData を実行すれば、同じ値をまた登録できます。SetData は対象要素のフォームを探し、SetFormData は setByJson に渡した data を直接操作します。この例では両方が同じフォームを指しています(データ操作、SetData、ClearFormData)。
通常の単一選択で change の有無を比べる
let changes = 0;
$('#ManualDispatchChoice')
.off('change.manualDispatchLab')
.on('change.manualDispatchLab', function () { changes += 1; });
$p.manualDispatchLab([
{ Method: 'SetValue', Target: '#ManualDispatchChoice', Value: 'b' }
]);
console.log(changes); // 0
$p.manualDispatchLab([
{ Method: 'Set', Target: '#ManualDispatchChoice', Value: 'a' }
]);
console.log(changes); // 1
console.log($p.data.ManualDispatchForm.ManualDispatchChoice); // a検索付き・複数選択ではない通常の単一選択の例です。Set はコントロールの解決後に $p.set を呼び、この種類の選択欄では change を発火させてから setData を実行します(Set の対象解決、単一選択とバッファ登録)。
実験を終えたら、フォームとこの例で追加した関数・バッファを削除します。
$('#ManualDispatchForm').remove();
delete $p.data.ManualDispatchForm;
delete $p.manualDispatchLab;