2022年4月29日金曜日

動的アクションのJavaScriptコードで使用するthisについて

 動的アクションのTrueアクションをJavaScriptでコーディングする際に、this.triggeringElement、this.browserEventなどが使用できます。この使い方を紹介します。

アクションとしてJavaScriptコードの実行を選択したときの、設定のコードのオンライン・ヘルプには、以下の記載があります。

  • this.triggeringElement
    • 動的アクションをトリガーした要素のDOMオブジェクトへの参照。
  • this.affectedElements
    • 影響を受けるすべての要素を含むjQueryオブジェクト。
  • this.action
    • アクション名と追加の属性値などの詳細を含むアクション・オブジェクト。
  • this.browserEvent
    • イベントをトリガーしたイベントのイベント・オブジェクト。ノート: ロード時、これは'load'と同等になります。
  • this.data
    • イベント・ハンドラから渡すことができるオプションの追加データ。
一般にOracle APEXでアプリケーションを開発している方は、HTML、CSS、JavaScriptはそれほど経験がない方が多いといわれています。なので、この説明だけではピンとこないようです。

先日作成したアプリケーションを使って、これらの属性を使ってみます。

そもそも、このthisは何か、から確認します。

TRUEアクションに以下のコードが記述されています。(ページ・アイテムへの値の移入を題材にとります。列への移入はコメント・アウトします。)


このように作成した動的アクションは、HTMLのソースとして以下のように出力されます。

<script type="text/javascript">
apex.da.initDaEventList = function(){
    apex.da.gEventList = [{
        "triggeringElementType":"COLUMN",
        "triggeringElement":"C11489677485938601",
        "triggeringRegionId":"test_grids",
        "isIGRegion":true,
        "bindType":"bind",
        "bindEventType":"click",
        "anyActionsFireOnInit":false,
        actionList [{
            "eventResult":true,
            "executeOnPageInit":false,
            "stopExecutionOnError":true,
            javascriptFunction:function (){
                $s("P1_CELL_VALUE",$v(this.triggeringElement));
            }
,
            "action":"NATIVE_JAVASCRIPT_CODE"
        }]
    }];
}
</script>

設定コードのJavaScriptの記述が、ファンクションとしてactionListに登録されています。thisはこのファンクションの実行コンテキストになります。

<script>から</script>の間に記載されている内容は、概ねページに作成された動的アクションの定義を転記しています。動的アクションの定義リストがapex.da.initDaEventListになります。このリストを受け取って、動的アクションを実行するコードはdynamic_actions_core.jsに含まれています。


dynamic_actions_core.jsは、すべてのAPEXのインストールに含まれています。(実際に、ページにロードされているのはミニファイされたdesktop_all.min.jsです。)

JavaScriptのコードを実行する部分は、以下のようにコーディングされています。
    /**
     * doAction function
     * Executes the action (pAction) on certain elements (pSelector)
     * @ignore
     */
    da.doAction = function( pContext, pSelector, pAction, pDynamicActionName, pResumeCallback ) {
        var lContext = {
            triggeringElement : pContext.triggeringElement,
            affectedElements  : $( pSelector, apex.gPageContext$ ),
            action            : pAction,
            browserEvent      : pContext.browserEvent,
            data              : pContext.data,
            resumeCallback    : pResumeCallback
        };

        // Call the javascript function if one is defined and pass the lContext object as this
        if ( pAction.javascriptFunction ) {

            // Log details of dynamic action fired out to the console (only outputs when running in debug mode)
            apex.debug.log( "Dynamic Action Fired: " + pDynamicActionName + " (" + pAction.action + ")", lContext );
            return pAction.javascriptFunction.call( lContext );
        }
    }; // doAction

変数IContextが、実行コンテキストになっていることが分かります。

では、IContextに含まれるtriggeringElementやbrowserEventは何か?ということになります。

動的アクションは以下のように定義されています。


指定したHTML要素(リージョンTest Gridsの列A)が、クリックされたときにアクションが実行されます。

よって、this.triggeringElementにはクリックされた列Aのセルへの参照が含まれます。this.browserEventにはクリックであるMouseEventが含まれます。MouseEventはEventから派生したインターフェースで、イベントの種類によってインターフェースは変わります。

TRUEアクションのコードにconsole.log(this.triggeringElement);を追加して、内容をJavaScriptコンソールに出力してみます。
console.log(this.triggeringElement);
$s("P1_CELL_VALUE",$v(this.triggeringElement));

対話グリッドの列Aをクリックすると、JavaScriptコンソールにクリックしたセルのHTML要素(inputタグ)が印刷されます。


this.triggeringElementとしてHTML要素、this.browserEventとしてMouseEventが渡されていることがわかったので、これを使ったコードを追加してみます。

Shiftキーを押してクリックしたときだけ、値をコピーするようにします。

this.triggeringElementはinputのHTML要素ですから、APEXが提供しているファンクション$vの代わりに.valueでも値を取ることができます。

コードは以下に変更します。

$s("P1_CELL_VALUE",this.triggeringElement.value);

クライアントの条件タイプJavaScript式を選択し、JavaScript式に以下を記述します。シフト・キーを押した状態でMouseEventが発生したときにtrueになります。

this.browserEvent.shiftKey


this.actionthis.affectedElementsthis.dataは、主にOracle APEXに依存した情報になります。

this.actionからは、呼び出されているTRUEアクションの定義を参照できます。プラグインを作成するようなケースを除き、参照することはないと思います。

this.affectedElementsは、アクション影響を受ける要素として設定されたHTML要素が(配列として)渡されます。今回のTRUEアクションは、影響を受ける要素P1_CELL_VALUEを設定して、次のように書き直すことができます。
let elem = this.affectedElements[0];
$s(elem,this.triggeringElement.value);

this.dataとして渡される値は動的アクションによって異なります。

例えば、対話グリッド選択を変更したときに発生するイベントで、動的アクションを作成します。


TRUEアクションとしてconsole.log(this.data);を実行し、内容を確認します。


this.dataには、対話グリッドのmodelと選択されたレコードが含まれていることが確認できます。

最後に、アプリケーション開発中であればthisの内容を確認するためにconsole.logを埋め込む必要はありません。開発者ツール・バーが開いている状態で、JavaScriptコンソールを開いていれば、動的アクションが実行される都度、thisの内容がコンソールに出力されます。


以上で、動的アクションのJavaScriptコードで使用するthisの紹介は終了です。

Oracle APEXのアプリケーション作成の参考になれば幸いです。