Let's say that when a user clicks on something, perhaps selecting
something from a DataTable or DataGrid, you want to call some server
side code, and then popup a modal panel which needs to show content
based on the new state setup by your server side call. In my case I
have a DataGrid showing a number of items, and when a user clicks on an
item I want to set the current selected item on a Seam component on the
server, and then popup a modal panel to display detailed information
about the item, and provide the user some actions within the modal
panel.
Looking at the solution it seems so simple, but for some reason it
took me hours of trying different combinations, orders, tags,
JavaScripts, etc... before I could get this to work correctly. I had
the panel appearing with the old data, or appearing with the old data
and then disappearing completely, only to show the so called new data
the next time I clicked on an item, or rendering on the page itself
below the footer, or not popping up at all, or popping up with null
data, or.... So I'm posting it up here for myself and anyone else who
runs into issues.
First, create your modal panel (rich:modalPanel). I do this in a
separate .xhtml file, as I will use the same model panel in various
pages throughout the site. In your modal-panel.xhtml file (or whatever
you choose to name it), start with a <ui:composition>
tag, define your RichFaces xml namespace (and any other JSF libs you'll be using), and then setup your <rich:modalPanel>
. You need to give the modalPanel a unique id, in this case we'll call it "myModalPanel".
<rich:modalPanel id="myModalPanel" autosized="true" zindex="2000">
Inside your modalPanel tag, you need to define an inner div. This is
the div which you will be rerendering after the server action is
complete. I use tags, as I'm using Seam. Ensure that any
references to backing beans or data that you want refreshed are within
these div tags. You must give this div a unique id as well, in this
case we'll call it "myModalDiv".
<s:div id="myModalDiv">
The one limitation that I've run into here, and if you know how to solve this, please let me know, is that the <f:facet>
tags for your header text and controls can't be inside this div, and
you can't put the div around the whole modalPanel (or it makes the
panel disappear when you rerender). As such you can't make anything
from the <f:facet>
s be updated on rerender. This is
preventing me from having the modal panel header displaying the current
selected item's name. Not great, but not the end of the world.
So inside this div you have your dynamic output. I have lots of
<h:outputText value="#{backingBean.selectedItem.property}" />
type entries in mine.
On your actual page where you will be displaying the modal panel from you need to include the modal-panel.xhtml file, I use a:
<a:include viewId="/modal-panel.xhtml" />
Then, I have my page, which includes a rich:dataGrid, and inside it has an <a:commandLink>
which creates the AJAX clickable item. This commandLink has to call the
backend action, display the modal panel, and rerender your div.
<a:commandLink id="showItem" action="#{backingBean.setSelectedItem(item)}"
oncomplete="Richfaces.showModalPanel('myModalPanel',{width:550, top:200});"
reRender="myModalDiv">
Click Here!
</a:commandLink>
This makes the panel display, and then the new content is rendered
in the panel. It seems to work just how I wanted it to. With the minor
annoyance of having to use a static modalPanel header.