以前にOracle APEXでHighchartsを使う方法やCKEditor5のInline Editorを使う方法を紹介しています。それと似た作業になります。
サンプル・データセットのEMP/DEPTに含まれる表EMPを、Grid.jsにて表示します。
Grid.js側のコードは、ExamplesのCustom HTTP clientの例を参考にして記述します。
この例のコメントとして、RESTサービスが返すべきデータのフォーマットが記載されています。
正直なところ、上記のコードからはフォーマットがピンと来なかったので、Examplesのコードに含まれているURLにアクセスして、出力されるレスポンスを確認しました。
表EMPのデータを上記のフォーマットで返すSELECT文は以下になります。
select
json_object(
'data' value coalesce(json_arrayagg(line),'[]') format json
, 'total' value count(*)
)
from (
select json_object(empno, ename, job, sal, comm, hiredate) as line
from emp
);
SQLワークショップのSQLコマンドより上記のSQLを実行することにより、出力されるJSONオブジェクトを確認できます。
上記のSELECT文の結果を返す、RESTfulサービスのGETハンドラを作成します。
SQLワークショップのRESTfulサービスを開きます。
モジュールgridjsを作成します。モジュール・パスは/gridjs/とします。続いてURIテンプレートemp/をモジュールgridjsに作成します。
テンプレートemp/にGETハンドラを作成します。ソースとして以下を記述します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
l_json clob; | |
begin | |
select | |
json_object( | |
'data' value coalesce(json_arrayagg(line),'[]') format json | |
, 'total' value count(*) | |
) into l_json | |
from ( | |
select json_object(empno, ename, job, sal, comm, hiredate) as line | |
from emp | |
); | |
htp.p(l_json); | |
end; |
完全なURLは、Grid.jsを初期化するコードにサーバー側のURLとして指定するため、コピーをして後で参照できるようにしておきます。
RESTfulサービスを、APEXセッションからのみ呼び出しができるように保護します。
ORDSの権限としてgridjsを作成します。ロールとしてRESTful Servicesを選択します。保護されたモジュールとしてgridjsを選択します。選択するロールはRESTful Servicesでなくてもかまいません(専用のロールを新規に作る方が望ましいでしょう)。ここで選択したロールを、APEXのユーザーに割り当てます。
ユーザーとグループの管理を開き、RESTfulサービスへアクセスするユーザーを編集します。グループ割当てとしてRESTful Servicesを割り当てます。
以上でデータのソースとなるRESTfulサービスの準備ができました。
APEXアプリケーションを作成し、Grid.jsを組み込みます。
アプリケーション作成ウィザードを起動し、空のアプリケーションを作成します。
アプリケーションの名前はGrid.jsとします。
アプリケーションが作成されます。
ページ・デザイナにてホーム・ページを開きます。
Grid.jsのドキュメントのInstallにに含まれるjsdelivrのセクションを参照し、以下の設定を行います。
ページ・プロパティのJavaScriptのファイルURLとして以下を設定します。
https://cdn.jsdelivr.net/npm/gridjs/dist/gridjs.umd.js
https://cdn.jsdelivr.net/npm/gridjs/dist/theme/mermaid.min.css
Bodyにグリッドを表示するリージョンを作成します。
識別のタイトルをGrid、タイプとして静的コンテンツを選択します。外観のテンプレートとして装飾の少ないBlank with Attributes (No Grid)を選択します。詳細の静的IDとしてgridを設定します。
作成したリージョンGridを対象として、Grid.jsを初期化します。
ページ・プロパティのJavaScriptのファンクションおよびグローバル変数の宣言として、以下を記述します。RESTfulサービスの認証に使用します。
let apexSession = apex.env.APP_ID + ',' + apex.env.APP_SESSION;
ページ・ロード時に実行として、以下を記述します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const grid = new gridjs.Grid({ | |
columns: [ | |
{ | |
id: "EMPNO", | |
name: "従業員番号" | |
}, | |
{ | |
id: "ENAME", | |
name: "従業員名" | |
}, | |
{ | |
id: "JOB", | |
name: "ジョブ" | |
}, | |
{ | |
id: "SAL", | |
name: "給与" | |
}, | |
{ | |
id: "COMM", | |
name: "手当" | |
}, | |
{ | |
id: "HIREDATE", | |
name: "採用日" | |
} | |
], | |
server: { | |
url: "&G_DATA_SOURCE_URL.", | |
data: (opts) => { | |
return new Promise((resolve, reject) => { | |
// let's implement our own HTTP client | |
const xhttp = new XMLHttpRequest(); | |
xhttp.onreadystatechange = function() { | |
if (this.readyState === 4) { | |
if (this.status === 200) { | |
const resp = JSON.parse(this.response); | |
// columnsのidを含めているのでJSONをそのまま返す。 | |
resolve( resp ); | |
} else { | |
reject(); | |
} | |
} | |
}; | |
xhttp.open("GET", opts.url, true); | |
xhttp.setRequestHeader("Apex-Session", apexSession); | |
xhttp.send(); | |
}); | |
} | |
} | |
/* , | |
pagination: { | |
limit: 5 | |
} | |
*/ | |
}).render(document.getElementById("grid")); | |
// グリッドをリフレッシュする。 | |
apex.actions.add([ | |
{ | |
name: "force-render", | |
action: function ( event, element, args ) { | |
grid.forceRender(); | |
} | |
} | |
]); |
コード中で使用されている置換文字列G_DATA_SOURCE_URLを、アプリケーション定義の置換に設定します。置換値はRESTfulサービスの完全なURLです。
グリッドをリフレッシュするボタンを作成します。
識別のボタン名をB_REFRESH、ラベルはリフレッシュとします。動作のアクションとして動的アクションで定義を選択します。詳細のカスタム属性としてdata-action="#action$force-render"を設定します。
Grid.jsのグリッドを初期化するリージョン、正確にはdiv要素に子要素が含まれていると初期化に失敗します。そのため、ここで作成するボタンB_REFRESHをリージョンGridに含めることはできません。エラーが発生しないようにするために、リージョンGridの静的IDを空白にし、ソースのHTMLコードとして
<div id="grid"></div>
を記述することもできます。
以上でAPEXアプリケーションへのGrid.jsの組み込みは完了です。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/gridjs-integration.zip
https://github.com/ujnak/apexapps/blob/master/exports/ORDS_REST_WKSP_APEXDEV_gridjs_2022_08_30.sql
Oracle APEXのアプリケーション作成の参考になれば幸いです。
追記
RESTfulサービスの代わりにAjaxコールバックを使った実装例です。
AjaxコールバックとしてプロセスGET_EMPを作成します。ソースのPL/SQLコードは、RESTfulサービスのGETハンドラのコードと同じです。
作成したAjaxコールバックを呼び出すように、ページ・プロパティのJavaScriptのページ・ロード時に実行を以下に変更します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const grid = new gridjs.Grid({ | |
columns: [ | |
{ | |
id: "EMPNO", | |
name: "従業員番号" | |
}, | |
{ | |
id: "ENAME", | |
name: "従業員名" | |
}, | |
{ | |
id: "JOB", | |
name: "ジョブ" | |
}, | |
{ | |
id: "SAL", | |
name: "給与" | |
}, | |
{ | |
id: "COMM", | |
name: "手当" | |
}, | |
{ | |
id: "HIREDATE", | |
name: "採用日" | |
} | |
], | |
server: { | |
data: () => { | |
return new Promise((resolve, reject) => { | |
apex.server.process( "GET_EMP", {}, | |
{ | |
success: function( resp ) { | |
resolve( resp ); | |
}, | |
error: function( jqXHR, textStatus, errorThrown ) { | |
reject(); | |
} | |
}); | |
}) | |
} | |
} | |
/* , | |
pagination: { | |
limit: 5 | |
} | |
*/ | |
}).render(document.getElementById("grid")); | |
// グリッドをリフレッシュする。 | |
apex.actions.add([ | |
{ | |
name: "force-render", | |
action: function ( event, element, args ) { | |
grid.forceRender(); | |
} | |
} | |
]); |
完