Unit 17 - 顯示訊息及對話框: 使用 PrimeFaces 元件

3 minute read

JSF 教學

Unit 17

問題

使用者點擊按鈕且系統處理商業邏輯完成後, 應用系統在 Browser 顯示訊息或者對話框.

訊息顯示的 UI 可以在分類成:

  • 可選擇性的點擊確認
  • 必要性的點擊確認
    • 例如: Dialog 或者 Modal Window

可選擇之方案

可選擇性的點擊確認的訊息顯示

訊息顯示後, 使用者的不需要中斷目前的操作, 回應訊息.

使用 PrimeFaces 的 p:growl facelet.

Src: Growl component @ PrimeFaces Showcase

必要性的點擊確認的訊息顯示

訊息顯示後, 使用者的被中斷目前的操作, 回應訊息.

制式對話框

組成包括:

  • 對話框標題
  • 訊息
  • 一個或多個按鈕

使用 PrimeFaces 的 p:confirmDialog facelet.

Src: ConfirmDialog component @ PrimeFaces Showcase

自訂對話框

使用 JSF 頁面做為對話框, JSF 頁面依照需求自訂。

使用 PrimeFaces 的 Dialog Framework.

Src: PrimeFaces Showcase

實作練習 1: 使用 PrimeFaces 的 p:growl facelet 顯示非強制性訊息

Step 建立一個 Java Web Project. 該專案使用 Maven builder.

Step 加入 JavaServer Faces framework 到專案

Step 在 pom.xml 加入 PrimeFaces 的 Dependency

1
2
3
4
5
<dependency>
    <groupId>org.primefaces</groupId>
    <artifactId>primefaces</artifactId>
    <version>7.0</version>
</dependency>

Step 建立 growl.xhtml. 加入以下的 codes:

1
2
3
4
5
6
7
<p:growl id="growl" showDetail="true">
    <p:autoUpdate />
</p:growl>
<h:form>
    <p:commandButton value="p:messages" 
                     action="#{messageBean.showMessage()}"/>
</h:form>

Step 建立一個 CDI Bean messageBean, 建立方法 showMessage():

1
2
3
4
5
6
7
8
9
10
11
public String showMessage() {
    //取得目前的 FacesContext
    FacesContext facesContext = FacesContext.getCurrentInstance();
    String clientId = "";
    // 建立訊息
    FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_INFO,
                "Info", "This is the information");
    // 將訊息加入 Context, 由 p:grawl 顯示
    facesContext.addMessage(clientId, facesMessage);
   return null;
}

使用 PrimeFaces 內的 jQuery

PrimeFaces 內已經內含 jQuery. 如果再用 <script> 引入外部的 jQuery.js 會導致錯誤.

解決方式

  • 如果頁面中有使用 PrimeFaces 的標籤, 則會自加引入 jQuery.js
  • 如果頁面中沒有使用, 則在該頁面中加引入 PrimeFaces 內的 jQuery.js
1
<h:outputScript library="primefaces" name="jquery/jquery.js" />

Ref: How to use jQuery and jQuery plugins with PrimeFaces

實作練習 2: 制式對話框(1)

使用 p:confirmDialog 製作制式對話框

新增以下程式碼到 confirmDialog.xhtml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<h:form>     
    <p:growl id="message" showDetail="true" />
    <!-- Mark 1 -->
    <p:commandButton type="button" onclick="PF('cd').show()" value="Destroy the World"/>
    <!-- Mark 2 -->
    <p:confirmDialog message="Are you sure about destroying the world?" 
                     header="Initiating destroy process" 
                     severity="alert" widgetVar="cd"
                     responsive="true">
    <!-- Mark 3 -->
        <p:commandButton value="Yes Sure" action="#{messageBean.showMessage()}" 
                         update="message" oncomplete="PF('cd').hide()"/>
        <p:commandButton value="Not Yet" onclick="PF('cd').hide();" type="button" />
    </p:confirmDialog>
    /h:form>

Mark 1 程式解說

  • p:commandButton 中使用 onclick 屬性指定按鈕點擊時要執行的 JavaScript.
  • PF('cd').show()PF 是 PrimeFaces 元件的選擇器, cd 則是使用 wigetVar 屬性定義的變數。這個變數在 p:confirmDialog 中被定義。show()p:confirmDialog widget 的方法, 可以開啟 dialog; 使用 close() 則可以關閉對話框。
  • 所以, 當點擊 Mark 1 下方的 p:commandButton 後, 會開啟 p:confirmDialog

Mark 2 程式解說

  • 使用 responsive 屬性, 依螢幕大小自動調整對話框的位置。

Mark 3 程式解說

  • Mark 3 的兩個 p:commandButton 是對話框中按鈕。
  • 第一個 p:commandButton 使用了三個屬性: action, update, oncomplete。當點擊此按鈕後的執行過程:
    1. 執行 action 屬性所關聯的 bean method
    2. 執行 AJAX 更新, 更新 update 屬性所指定的元素 id
    3. 執行 oncomplete 屬性的 JavaScript 程式碼

進一步參考 Confirm Dialog @ PrimeFaces Documentation

實作練習 3: 制式對話框(2)

Use PrimeFaces.current().dialog().showMessageDynamic(facesMessage) to show message.

Step. 建立頁面 dialogMessage.xhtml

1
2
3
4
<h:form>
    <p:commandButton value='Notification' 
    action='#{messageBean.showDialogMessage("Hello")}' />
</h:form>

Step. 建立 action method

1
2
3
4
public void showDialogMessage(String info){
    FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_INFO, info, info + " more details ...");
    PrimeFaces.current().dialog().showMessageDynamic(facesMessage);
}

實作練習 4: 自訂對話框

Step 建立頁面 /dialogs/myDialog.xhml, 其 head 及 body 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<h:head>
    <!-- Mark 1 -->
    <title>Your Dialog Title</title>
</h:head>
<h:body>
    <!-- Mark 2 -->
    <h1> #{param['dialog-title']} </h1>
    <p>
        #{param['dialog-message']}
    </p>
    <p>
        <h:form> 
        <!-- Mark 3 -->
            <p:commandButton value="Train" action='#{messageBean.selectOption("train")}' />
            <p:commandButton value="Bus" action='#{messageBean.selectOption("Bus")}'/>
            <p:commandButton value="No Idea" action='#{messageBean.selectOption("No selection")}'/>
        </h:form>
    </p>
</h:body>

Mark 1

  • 頁面的 title 元素的內容將成為對話框的標題

Mark 2

  • 顯示此對話框時所傳送的請求參數。使用 param 自動變數取得 HTTP Request 中的參數。 param 為 Map 資料結構, [] 內為 key 值。

Mark 3

  • 對話框的按鈕
  • 點擊後執行 bean method selectOption(option:String), 此方法會:
    1. 取得傳入參數
    2. 將傳入參數傳回給 host page, 使用 AJAX 方式
    3. 關閉對話框

Step 建立對話框的 host page: dialogFramework

1
2
3
4
5
6
7
8
<h:form>
    <p:commandButton value="Show Dialog" action="#{messageBean.showDialog()}">
         <p:ajax event="dialogReturn" listener="#{messageBean.onSelectTransportation}" 
                 update="yourSelection"/>
    </p:commandButton>
</h:form>
Your Selection: <h:outputText id="yourSelection"
    value="#{messageBean.selectedTransportation}" />
  • 點擊 p:commandButton 會執行 showDialog() 方法, 開啟對話框
  • p:ajax 讓我們監聽關閉對話框所產生的 AJAX event dialogReturn
  • p:ajaxlistener 屬性指定 event handler, 執行事件處理邏輯
  • p:ajaxupdate 屬性指定 AJAX Request 處理完成後, 要更新的頁面元素的 ID

Step 建立開啟、關閉及取得對話框回傳值的 action methods 及 action listener

建立開啟對話框的 bean method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public String showDialog() {
    // Dialog Options
    Map<String, Object> options = new HashMap<String, Object>();
    options.put("modal", true);
    options.put("width", 640);
    options.put("height", 340);
    options.put("contentWidth", "100%");
    options.put("contentHeight", "100%");
    options.put("headerElement", "customheader");
  
    // the JSF page to open as a dialog
    String outcome = "/dialogs/myDialog";
  
    // Request parameters sent to the target JSF page
    Map<String, List<String>> params = new HashMap<>();    
    params.put("dialog-title", Arrays.asList("Select your transportation"));
    params.put("dialog-message", Arrays.asList("Which one do you prefer?"));
  
    // Open the target JSF page as a dialog
    PrimeFaces.current().dialog().openDynamic(outcome, options, params);
  
    return null;
}
  • 在 Host Page 的 action method 執行
    1
    
    PrimeFaces.current().dialog().openDynamic(outcome, options, params);
    

    以開啟對話框。

建立點擊對話框按鈕時執行的 action method

1
2
3
4
public String selectOption(String option){
    PrimeFaces.current().dialog().closeDynamic(option);
    return null;
}
  • 在 Dialog Page 的 action method 執行:
    1
    
    PrimeFaces.current().dialog().closeDynamic(option);
    

    以關閉對話框。

  • closeDynamic 方法中的參數將被傳入到產生的 AJAX event, 供 Host Page 使用

建立處理 dialogReturn AJAX event 的 event listener 方法

1
2
3
4
public void onSelectTransportation(SelectEvent event){
        String value = (String) event.getObject();
        this.selectedTransportation = value;
}

Updated: