Статьи

PrimeFaces: открытие внешних страниц в динамически генерируемом диалоге

Я уже писал об одном рецепте в готовящейся к выпуску 2. Поваренной книге PrimeFaces . В этом посте я хотел бы опубликовать второй рецепт о небольшой платформе под названием Dialog Framework . Мне лично это нравится, потому что я помню свои дорогостоящие попытки сделать то же самое с помощью Struts Framework. Если вы хотите загрузить внешнюю страницу во всплывающее окно и отправить на нее некоторые данные, вам нужно было вызвать window.open со скрытой формой, установить переданные значения в скрытые поля, отправить форму на внешнюю страницу с помощью JavaScript и подождать, пока страница готова к использованию в window.onload или document.ready . Много ручной работы. PrimeFaces делает эту работу за вас и, кроме того, предоставляет p:dialog красивый пользовательский интерфейс в качестве замены всплывающего окна.

Регулярное использование диалога PrimeFaces — декларативный подход с p:dialog . Помимо этого декларативного подхода, существует и программный подход. Программный подход основан на программном API, в котором диалоги создаются и уничтожаются во время выполнения. Это называется Dialog Framework . Dialog Framework используется для открытия внешних страниц в динамически генерируемом диалоге. Использование довольно простое, RequestContext предоставляет два метода: openDialog и closeDialog которые позволяют открывать и закрывать динамические диалоги. Кроме того, Dialog Framework позволяет передавать данные обратно со страницы, отображаемой в диалоговом окне, на страницу вызывающего абонента.

В этом рецепте мы продемонстрируем все функции, доступные в Dialog Framework. Мы откроем диалог с опциями программно и передадим параметры на страницу, отображаемую в этом диалоге. Мы также встретимся с возможностью общения между исходной (вызывающей) страницей и диалогом.

Готовиться

Для Dialog Framework требуется следующая конфигурация в faces-config.xml :

1
2
3
4
5
<application>
    <action-listener>org.primefaces.application.DialogActionListener</action-listener>
    <navigation-handler>org.primefaces.application.DialogNavigationHandler</navigation-handler>
    <view-handler>org.primefaces.application.DialogViewHandler</view-handler>
</application>

Как это сделать…

Мы разработаем страницу с переключателями, чтобы выбрать одну из доступных книг PrimeFaces для рейтинга. Сам рейтинг происходит в диалоге после нажатия на кнопку « Rate the selected book .

3427_11_04

Фрагмент кода XHTML на снимок экрана приведен ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<p:messages id="messages" showSummary="true" showDetail="false"/>
 
<p:selectOneRadio id="books" layout="pageDirection" value="#{dialogFrameworkBean.bookName}">
    <f:selectItem itemLabel="PrimeFaces Cookbook" itemValue="PrimeFaces Cookbook"/>
    <f:selectItem itemLabel="PrimeFaces Starter" itemValue="PrimeFaces Starter"/>
    <f:selectItem itemLabel="PrimeFaces Beginner's Guide" itemValue="PrimeFaces Beginner's Guide"/>
    <f:selectItem itemLabel="PrimeFaces Blueprints" itemValue="PrimeFaces Blueprints"/>
</p:selectOneRadio>
 
<p:commandButton value="Rate the selected book"
            process="@this books"
            actionListener="#{dialogFrameworkBean.showRatingDialog}"
            style="margin-top: 15px">
    <p:ajax event="dialogReturn" update="messages" listener="#{dialogFrameworkBean.onDialogReturn}"/>
</p:commandButton>

Страница в диалоговом окне представляет собой полную страницу bookRating.xhtml с компонентом рейтинга p:rating . Он также показывает название книги, выбранной для рейтинга.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:p="http://primefaces.org/ui">
<f:view contentType="text/html" locale="en">
    <f:metadata>
        <f:viewParam name="bookName" value="#{bookRatingBean.bookName}"/>
    </f:metadata>
    <h:head>
        <title>Rate the book!</title>
    </h:head>
    <h:body>
        <h:form>
            What is your rating for the book <strong>#{bookRatingBean.bookName}</strong>?
 
            <p/>
 
            <p:rating id="rating">
                <p:ajax event="rate" listener="#{bookRatingBean.onrate}"/>
                <p:ajax event="cancel" listener="#{bookRatingBean.oncancel}"/>
            </p:rating>
        </h:form>
    </h:body>
</f:view>
</html>

Следующий скриншот демонстрирует, как выглядит диалог.

3427_11_05

Щелчок по звездочке рейтинга или символ отмены закрывает диалог. На странице источника (звонящего) отображается сообщение с выбранным значением рейтинга в диапазоне от 0 до 5.

3427_11_06

Самая интересная часть — логика в бобах. Компонент DialogFrameworkBean открывает страницу рейтинга в диалоговом окне, вызывая метод openDialog() с результатом, параметрами и параметрами POST для экземпляра RequestContext . Кроме того, bean-компонент определяет прослушиватель AJAX onDialogReturn() который вызывается, когда данные (выбранный рейтинг) возвращаются из диалога после его закрытия.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Named
@ViewScoped
public class DialogFrameworkBean implements Serializable {
 
    private String bookName;
 
    public void showRatingDialog() {
        Map<String, Object> options = new HashMap<String, Object>();
        options.put("modal", true);
        options.put("draggable", false);
        options.put("resizable", false);
        options.put("contentWidth", 500);
        options.put("contentHeight", 100);
        options.put("includeViewParams", true);
 
        Map<String, List<String>> params = new HashMap<String, List<String>>();
        List<String> values = new ArrayList<String>();
        values.add(bookName);
        params.put("bookName", values);
 
        RequestContext.getCurrentInstance().openDialog("/views/chapter11/bookRating", options, params);
    }
 
    public void onDialogReturn(SelectEvent event) {
        Object rating = event.getObject();
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "You rated the book with " + rating, null);
 
        FacesContext.getCurrentInstance().addMessage(null, message);
    }
 
    // getters / setters
    ...
}

Компонент BookRatingBean определяет двух слушателей для Rating component . Они вызываются, когда пользователь нажимает на звездочку и символ отмены соответственно. Мы вызываем closeDialog() для экземпляра RequestContext чтобы запустить закрытие диалога и передать текущее значение рейтинга упомянутому слушателю onDialogReturn() .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
@Named
@RequestScoped
public class BookRatingBean {
 
    private String bookName;
 
    public void onrate(RateEvent rateEvent) {
        RequestContext.getCurrentInstance().closeDialog(rateEvent.getRating());
    }
 
    public void oncancel() {
        RequestContext.getCurrentInstance().closeDialog(0);
    }
 
    // getters / setters
    ...
}

Как это работает…

RequestContext предоставляет два метода с одинаковым именем openDialog для динамического открытия диалога во время выполнения. Первый имеет только один параметр — логический результат, используемый для разрешения случая навигации. Второй имеет три параметра — результат, параметры конфигурации диалога и параметры, которые отправляются в представление, отображаемое в диалоге. Мы использовали второй вариант в примере. Опции помещаются в Map как ключ, пары значений. Параметры также помещаются в Map . В нашем случае мы ставим название выбранной книги. После этого имя получено на странице bookRating.xhtml через f:viewParam . f:viewParam устанавливает переданный параметр в BookRatingBean , чтобы он был доступен в заголовке над компонентом Rating .

Совет: Пожалуйста, обратитесь к Руководству пользователя PrimeFaces, чтобы увидеть полный список поддерживаемых параметров конфигурации диалога.

Давайте пройдем через жизненный цикл запрос-ответ. Как только ответ получен от запроса, вызванного командной кнопкой, создается диалог с iframe внутри. URL-адрес iframe указывает на полную страницу, в нашем случае bookRating.xhtml . Страница будет перемещена вниз и показана в диалоговом окне. Как видите, всегда есть два запроса: первый начальный POST и второй GET, отправленный iframe. Обратите внимание, что Dialog Framework работает только с начальными AJAX-запросами. Не AJAX-запрос игнорируется. Также обратите внимание, что заголовок диалога взят из HTML-элемента title .

Как мы уже упоминали выше, диалог можно закрыть программным способом, invoking метод closeDialog для экземпляра RequestContext . На странице вызывающей стороны кнопка, запускающая диалог, должна иметь прослушиватель AJAX, чтобы событие dialogReturn могло получать любые данные из диалога. Данные передаются в качестве параметра в метод closeDialog(Object data) . В этом примере мы передаем положительное целочисленное значение rateEvent.getRating() или 0 .