1. User Story
2. 原理
在 Oracle Apex 的 page 的 DOM 中新增一個元素, 用來顯示通知訊息。
於載入頁面時, 由 page/application process 輸出 JavaScript code, 要求 browser 執行 JavaScript code, 以顯示通知訊息。
使用 JQuery, 先選擇先前新增的元素, 再使用 JQuery 的方法 show().delay(5000).fadeOut()
來顯示通知訊息。
3. 實作步驟
Step 1: 在 App 的 Navigation Tool Bar 中新增一個 Icon, 做為訊息通知的父元素
在 Image/Class 欄位中, 除了 Icon class name 之外, 還要加上一個自訂的 class name msg-alert
, 以便於 JavaScript code 中選擇此元素。
Step 2: 設定傳訊息通知 CSS
我們會在相對於父元素的某個位置, 顯示訊息通知。
使用 absolute
定位, 並設定 top
, right
的值, 來控制訊息通知的位置。 使用 absolute
定位, 不會佔據父元素的位置, 會浮在父元素的上方。 「訊息通知」 會顯示在父元素下方 30px 的位置, 並靠右對齊。
預設不顯示 (display:none
), 並設定背景顏色, 文字顏色, 邊框等樣式。 之後, 我們會使用 JavaScript code, 來控制「訊息通知」的顯示與消失。
所需的 CSS 如下:
Copy .msg-notification {
display : none ;
position : absolute ;
top : 60 px ;
right : 0 px ;
color : black ;
background-color : lightyellow ;
padding : 10 px ;
border : 1 px solid #ccc ;
border-radius : 5 px ;
}
Step 3: 將 CSS 加入到 App 的靜態檔案中, 並將其引入到 App 中
Path: Shared Components > Static Application Files > (B)Create File
輸入 File Name 並按下 Create 按鈕, 可建立一個新的 CSS file 並編輯其內容。
若已在外部編輯好 CSS file, 可直接 Drag & Drop 檔案到此頁面中。
我們在 File Name 中輸入 notification.css
:
接著, 在 CSS file 中貼上上述的 CSS code:
Oracle Apex 會 minify CSS code, 以減少檔案大小。在 File Name 欄位下方有一個 Reference 欄位, 可以看到 minify 後的 CSS 連結。
複制此連結供後續使用。
接著要將 CSS 引入到 App 中。
路徑 Shared Components > User Interface Attributes > CSS
在 File URLs 欄位中, 貼上剛才複制的 minify 後的 CSS 連結。
Step 4: 設定新增「訊息通知」元素的 JavaScript code 及其它輔助 function
在頁面載入時, 會執行以下動作:
選取父元素, 使用 .msg-alert
元素的上兩層元素為父元素。
建立一個新的 div 元素, 並設定其內容為 Message Placeholder
設定 div 元素的 class name 為 msg-notification
, 以便套用 CSS 樣式
此外, 定義一個輔助 function showMessage(message)
, 用來顯示訊息通知。
此 function 會選取 class name 為 msg-notification
的元素, 並設定其內容為 message 引數的值。 最後, 使用 JQuery 的方法 show().delay(5000).fadeOut()
來顯示訊息通知。
message
引數的內容, 除了文字之外, 也可以含有 HTML 元素, 例如 <a href="...">link</a>
, 因為 innerHTML
會將其解析為 HTML 元素。
Copy /**
* Create a new div element and position it relative to the msg-alert element.
*
* The following code will be executed when the page is loaded.
*/
// 1. Get the parent element. In this case, it is the .msg-alert element
let msgAlert = document .querySelector ( '.msg-alert' );
// 不可以直接在msg-alert元素上添加新元素,因为 msg-alert 是 anchor 元素。若在 anchor 元素上添加 anchor 元素, 子元素的 anchor 無法被點擊。
let parent = msgAlert . parentElement .parentElement;
// 2. create a new div element for the message
let msgDiv = document .createElement ( 'div' );
msgDiv .innerHTML = 'Message Placeholder' ;
// 3. set the class name for the div element
// The class name should be the same as the one in the CSS file in the previous step.
msgDiv . classList .add ( 'msg-notification' );
// 4. append the div element to the body
parent .appendChild (msgDiv);
// The helper function to show the message
function showMessage (message) {
let msgDiv = document .querySelector ( '.msg-notification' );
msgDiv .innerHTML = message;
$ ( '.msg-notification' ) .show () .delay ( 5000 ) .fadeOut ();
}
此 JS 程式會將「訊息通知」元素加下 <li class="t-NavigationBar-item>
元素內, 而不是 <a class="msg-alert">
元素內, 以避免在 anchor 元素內添加 anchor 元素。
Step 5: 將 JavaScript code 加入到 App 的靜態檔案中, 並將其引入到 App 中
此步驟的操作方式和 Step 3 類似。
建立 static JavaScript file 的路徑: Shared Components > Static Application Files > (B)Create File
將前一步驟的 JavaScript code 複制貼上到此檔案中:
複製 minify 後的 JavaScript 連結, 供後續使用。
接著, 將 JavaScript file 引入到 App 中, 路徑: Shared Components > User Interface Attributes > JavaScript
Step 6: 觀察 custom js 及 css file 的載入順序。
Custom CSS file 會在 Apex Page 中的 <head>
中引入
Custom JS file 會在 Apex Page 中的 <body>
的最後引入
我們後續用 PL/SQL code 來輸出的 JavaScript code 會在 custom js file 之後載入。 如此, 我們才能正確的呼叫 showMessage()
function。
Step 7: 在 App 的 Page 中, 新增一個 Application Process, 用來輸出 JavaScript code
我們會去 test_orders
table 中, 查詢是否有狀態 new
的訂單。
如果有一筆以上的訂單, 則輸出文字 You have [n] new orders.
.
這個 App Process 的執行時間點設為 On Load: After Footer (page template footer)
. 這個時間點設定後重要, 因為要確保 先前的 custom js file 已經載入, 才能呼叫 showMessage()
function。
若將 App Process 的執行時間點設為 On Load: After Body Regions
, 則會發生錯誤, 因為 custom js file 尚未載入。
所需要的 PL/SQL code 如下:
Copy declare
v_order_count number ;
-- v_js_str varchar2(1000) := '<script> apex.message.alert("#MSG#"); </script>';
-- Call the javascript function showMessage
v_js_str varchar2 ( 1000 ) : = '<script> showMessage("#MSG#") </script>' ;
v_msg varchar2 ( 1000 );
begin
apex_debug.enable(apex_debug.c_log_level_info);
-- Check if any new orders in the test_orders table
select count ( * ) into v_order_count
from test_orders
where order_status = 'new' ;
if v_order_count > 0 then
-- show message
v_msg : = 'You have ' || v_order_count || ' orders.' ;
v_js_str : = replace (v_js_str, '#MSG#' , v_msg);
apex_debug.info( '== Notification: %s' , v_js_str);
htp.p(v_js_str);
end if ;
end ;
在上述的 PL/SQL code 中, 使用 htp.p()
來輸出 JavaScript code, 以呼叫 showMessage()
function。 這會在 Page 中輸出一段 JavaScript code, 例如:
Copy < script > showMessage("You have 1 orders.") </ script >
如此, 便會呼叫 showMessage()
function, 並顯示訊息通知。
要新增 Application Process, 路徑: App > Shared Components > Application Processes > (B)Create
接著設定 Process 的 Process Point
及 Name:
再設定 Process 的 Source, 將上述的 PL/SQL code 貼上:
若要限制此 Process 的執行範圍, 可以設定 Conditions
:
例如, 只有在特定的 Page 中執行此 Process:
Step 8: 測試
登入 APP 後, 進到首頁或任何頁面, 若 test_orders
table 中有狀態為 new
的訂單, 則會顯示訊息通知。
4. 顯示可點擊的訊息通知
修改前述幾個地方可以讓「訊息通知」內含有可點擊的連結, 例如點擊後查看最新的一筆訂單。
JavaScript 和 CSS 的部分不需要修改, 只需要修改 PL/SQL code。
我們首先將產生「訊息通知」的動作抽取出來, 成為 2 個 local (nested) functions.
showOrderCount
function 回傳有新訂單的訊息字串
showNewestOrderURL
function 回傳最新訂單的 URL, user 可以點擊連結查看最新的訂單。
showOrderCount
function 的內容如下:
Copy function showOrderCount(p_order_count in number ) return varchar2 is
begin
return '<p> You have ' || p_order_count || ' orders. </p>' ;
end ;
showNewestOrderURL
function 的內容如下:
Copy function showNewestOrderURL(p_page_id number , p_item_name varchar2 , p_order_id number ) RETURN varchar2 is
l_msg varchar2 ( 2000 );
l_url varchar2 ( 2000 );
begin
l_url : = apex_page.get_url(p_page => p_page_id,
p_items => p_item_name,
p_values => p_order_id);
l_msg : = q '[<p><a href=' ] ' || l_url || q' [' aria-hidden='false' >] ' || ' 您有最新訂單 ID ' || p_order_id || ' </ a > </ p > ';
return l_msg;
end;
此程式中的重點:
使用 apex_page.get_url()
來取得 URL. p_page
是目的頁面編號, p_items
是目的頁面的 item name 同時也是 primary key item, p_values
是 primary key 的值。
l_msg
是產生的 anchor 元素. 組合 URL 字串時, 屬性值要用單引號包住, 而不是雙引號。因為 PL/SQL 的 htp.p
產生字串內容時是使用雙引號。
所以, 修改後的 PL/SQL code 如下:
Copy declare
v_order_count number ;
v_order_id number ;
-- v_js_str varchar2(1000) := '<script> apex.message.alert("#MSG#"); </script>';
-- Call the javascript function showMessage
v_js_str varchar2 ( 1000 ) : = '<script> showMessage("#MSG#") </script>' ;
v_msg varchar2 ( 1000 );
function showOrderCount(p_order_count in number ) return varchar2 is
begin
return '<p> You have ' || p_order_count || ' orders. </p>' ;
end ;
function showNewestOrderURL(p_page_id number , p_item_name varchar2 , p_order_id number ) RETURN varchar2 is
l_msg varchar2 ( 2000 );
l_url varchar2 ( 2000 );
begin
l_url : = apex_page.get_url(p_page => p_page_id,
p_items => p_item_name,
p_values => p_order_id);
l_msg : = q '[<p><a href=' ] ' || l_url || q' [' aria-hidden='false' >] ' || ' 您有最新訂單 ID ' || p_order_id || ' </ a > </ p > ';
return l_msg;
end;
begin
apex_debug.enable(apex_debug.c_log_level_info);
-- Check if any new orders in the test_orders table
-- Select the total number of new orders
select count(*) into v_order_count
from test_orders
where order_status = ' new ';
-- Select the newest order id
select order_id into v_order_id
from test_orders
where order_status = ' new '
order by order_datetime desc
fetch first 1 row only;
if v_order_count > 0 then
-- show message
v_msg := showOrderCount(v_order_count);
-- Assume the page 2 display the order detail
v_msg := v_msg || showNewestOrderURL(2, ' P2_ORDER_ID ', v_order_id);
v_js_str := replace(v_js_str, ' #MSG# ', v_msg);
apex_debug.info(' == Notification: %s ', v_js_str);
htp.p(v_js_str);
end if;
end;
5. 總結
透過 JavaScript code, 我們在 Navigation Tool Bar 的某個元素下,新增一個元素,用來顯示訊息通知。
這些需要的 JavaScript code 和 CSS code, 上傳到 App 的靜態檔案中, 並引入到 App 中。
使用 PL/SQL code, 在 App Process 中輸出 JavaScript code, 以呼叫 JavaScript function, 來顯示訊息通知。
若要產生可點擊的訊息通知, 可以在 PL/SQL code 中, 產生包含 anchor 元素的 HTML 字串。
使用 apex_page.get_url()
來產生 URL 字串, 以便使用者點擊連結查看最新的訂單。