PrimeFaces: Opening external pages in dynamically generated dialog
I already blogged about one recipe in the upcomming 2. edition of the PrimeFaces Cookbook. In this post, I would like to post the second recipe about a small framework called Dialog Framework
. I personally like it because I remember my costly effort to do the same thing with the Struts Framework. When you wanted to load an external page into a popup and submit some data to this page, you had to call window.open
with an hidden form, set passed values into hidden fields, submit the form to the external page via JavaScript and wait until the page is ready to use in window.onload
or document.ready
. A lot of manuelly work. PrimeFaces does this job for you and, in addition, provides with p:dialog
a beautiful user interface as replacement for popup.
The regular usage of PrimeFaces’ dialog is a declarative approach with p:dialog
. Beside this declarative approach, there is a programmatic approach as well. The programmatic approach is based on a programmatic API where dialogs are created and destroyed at runtime. It is called Dialog Framework
. The Dialog Framework is used to open external pages in dynamically generated dialog. The usage is quite simple, RequestContext
provide two methods: openDialog
and closeDialog
that allow opening and closing dynamic dialogs. Furthermore, the Dialog Framework makes possible to pass data back from the page displayed in the dialog to the caller page.
In this recipe, we will demonstrate all features available in the Dialog Framework. We will open a dialog with options programmatically and pass parameters to the page displayed in this dialog. We will also meet the possibility for communicating between the source (caller) page and the dialog.
Getting ready
Dialog Framework requires the following configuration in faces-config.xml
:
<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>
How to do it…
We will develop a page with radio buttons to select one available PrimeFaces’ book for rating. The rating itself happens in a dialog after a click on the button Rate the selected book
.
The XHTML snippet to the screenshot is listed below.
<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>
The page in the dialog is a full page bookRating.xhtml
with a Rating component p:rating
. It also shows the name of the book selected for rating.
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" 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>
The next screenshot demonstrates how the dialog looks like.
A click on a rating star or the cancel symbol closes the dialog. The source (caller) page displays a message with the selected rating value in the range from 0 till 5.
The most interesting part is the logic in beans. The bean DialogFrameworkBean
opens the rating page within the dialog by invoking the method openDialog()
with the outcome, options and POST parameters on a RequestContext
instance. Furthermore, the bean defines an AJAX listener onDialogReturn()
which is invoked when the data (selected rating) is returned from the dialog after it was closed.
@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 ... }
The bean BookRatingBean
defines two listeners for the Rating component
. They are invoked when the user clicks on a star and the cancel symbol respectively. We call there closeDialog()
on a RequestContext
instance to trigger the dialog closing and to pass the current rating value to the mentioned listener onDialogReturn()
.
@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 ... }
How it works…
The RequestContext
provides two methods of the same name openDialog
to open a dialog dynamically at runtime. The first one only has one parameter – the logical outcome used to resolve a navigation case. The second one has three parameters – outcome, dialog’s configuration options and parameters that are sent to the view displayed in the dialog. We used the second variant in the example. The options are put into a Map
as key, value pairs. The parameters are put into a Map
too. In our case, we put the name of the selected book. After that, the name is received in the dialog’s page bookRating.xhtml
via the f:viewParam
. f:viewParam
sets the transferred parameter into the BookRatingBean
, so that it is available in the heading above the Rating
component.
Tip: Please refer the PrimeFaces User’s Guide to see a full list of supported dialog’s configuration options.
Let us go through the request-response life cycle. Once the response is received from the request caused by the command button, a dialog gets created with an iframe
inside. The URL of the iframe
points to the full page, in our case bookRating.xhtml
. The page will be streamed down and shown in the dialog. As you can see, there are always two requests: the first initial POST and the second GET sending by iframe. Note that the Dialog Framework only works with initial AJAX requests. Non-AJAX request are ignored. Please also note the the title of the dialog is taken from the HTML title
element.
As we already mentioned above, the dialog can be closed programmatically by invoking
the method closeDialog
on a RequestContext
instance. On the caller page, the button that triggers the dialog needs to have an AJAX listener for the dialogReturn
event to be able to receive any data from the dialog. The data is passed as parameter to the method closeDialog(Object data)
. In the example, we pass either a positive integer value rateEvent.getRating()
or 0
.
Reference: | PrimeFaces: Opening external pages in dynamically generated dialog from our JCG partner Oleg Varaksin at the Thoughts on software development blog. |
Hello, there is a bug when opening dialog from managedBean. i set closable to false in the map,
map.put(“closable”, false); (too map.put(“closable”, “false”);
but the button close[X] appears in dialog. i also tested
map.put(“toolbar”, false);
map.put(“showCloseIcon”, false); …..
Plz any help
I didn’t know about the code in faces-config.xml. Thankyou very much Mr.Varaksin.