Displaying and Rerendering a RichFaces ModalPanel from a commandLink
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
<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.
March 9th, 2008 at 4:27 pm
Hi,
I just faced a similar problem, and used a similar solution, with a panelGrid instead of a div. I could not use any parameter in my commandLink action, I dont know how you got this working (action=”#{backingBean.setSelectedItem(item)}”). I had to call a method without parameter, and get the selectedItem from the backing bean.
To update the modalPanel header, simply add an ID to the header outputText (or other elements), and add this ID to the rerender attribute on your commandLink :
(…)
Click Here!
March 9th, 2008 at 6:49 pm
Looks like Wordpress ate some of your code there, sorry about that.
Thanks for the info on the id in the header. Totally missed that one and it works perfectly! Thanks!
Being able to pass params in the action is a JBoss EL feature, not available in normal EL. I’m using Seam on JBoss so it’s available for me.
March 11th, 2008 at 12:55 am
Hi,
Thanks a lot for the great tip.
I have tried using h:inputText inside the modal div , but the modal panel renders it without a value but using
h:outputText renders the value quite correctly.
Have you tried such a scenario?
(am using Seam)
Cheers
March 11th, 2008 at 11:52 am
Richard,
I haven’t tried using inputText inside the modal yet. I may need to do that in the near future though. I’m not sure why it wouldn’t work though… Hmm. I’ll reply back if I am able to get it to work.
March 13th, 2008 at 5:18 pm
The following JSF component organization is working for me. This organization enables the controls facet in the modal panel.
Link to invoke the modalPanel:
<a4j:commandLink action="#{backingBean.setSelectedItem(item)}" onclick="javascript:Richfaces.showModalPanel('editSecurityGroup',{width:450,height:470})" reRender="editSecurityGroupForm"> <h:outputText value="#{messages['action.add']}" styleClass="linkText"/> </a4j:commandLink>And now the ModalPanel, same aproach as yours, in a different xhtml page:
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:rich="http://richfaces.org/rich" xmlns:a4j="http://richfaces.org/a4j"> <rich:modalPanel id="editSecurityGroup"> <f:facet name="header"> <h:outputLabel value="#{messages['maintainSecurityGroups.securityGroup']}"/> </f:facet> <f:facet name="controls"> <h:graphicImage value="/img/icons/xtiny/close.png" styleClass="linkImage"/> </f:facet> <h:form id="editSecurityGroupForm"> PLEASE PUT YOUR COMPONENTS HERE ! </h:form> </rich:modalPanel> </ui:composition>And the way I am including the modalPanel inside the main page. Note that I am using two different forms one for the main composition and one for modalPanel. The following inclusion can not be done inside the main form, because a know nested form in some broswer (i.e. Internet Explorer)
Hope this helps.
Greetings from Ecuador
March 14th, 2008 at 12:00 pm
Hi all,
I’m having a similar problem with a datatable and stumbled across this blog. I have a rich datatable with each row as a “match” object. Each match has a “nodeId” property. I need to be able to click on each row and have that nodeId show up as part of a modalPanel.
I’m using a rich component control to try to accomplish this:
<rich:componentControl event="onRowClick" for="assignmentPanel" operation="show"> <f:param value="#{match.nodeId}" name="nodeId"/> </rich:componentControl>Where assignmentPanel is my modal dialog. It’s patterned after this demo:
http://livedemo.exadel.com/richfaces-demo/richfaces/componentControl.jsf?c=componentControl
but doesn’t work at all for a Modal. Instead of displaying the proper nodeId, it displays {nodeId} Any ideas? Thanks.
March 14th, 2008 at 12:25 pm
Hi Rich,
can you post the rest of your xhtml code including the modal panel? I can’t promise I’ll know the answer, but I’m happy to take a look at it!
Devon
March 15th, 2008 at 9:14 am
Hi rich,
Tell me are you working with EntityHome components?. If it is like that, The only thing you have to do is send the corresponding param that will be the entityId in the EntityHome component. This will tell that component which component is being
<a4j:commandLink onclick="javascript:Richfaces.showModalPanel('editSecurityGroup',{width:450,height:470})" title="#{messages['tip.editSecurityGroup']}" reRender="editSecurityGroupForm"> <h:outputText value="#{messages['action.edit']}" styleClass="linkText"/> <s:conversationPropagation type="begin" /> <f:param name="securityGroupId" value="#{securityGroup.id}"/> </a4j:commandLink>But, I discovered that the problem could be due to one of these things:
The conversations are not well managed: Check the complete conversation stablished in the user transaction and the begin and end points. Usually when you have a table and after one action Edits the selected object the right place to begin the conversation is inside the action. -Check the attached post-
Check the components order inside the panel form, If you switch the order of the form with the modalPanel components in the xhtml page that panel won’t work. That was making me nuts almost for a complete day.
Let me know how are you going.
Cheers
March 15th, 2008 at 4:57 pm
Hi Devon,
You mentioned that you wanted to know how to update the text inside the <f:facet> tag. The following code works in my web app:
<f:facet name=”header”>
<a4j:outputPanel ajaxRendered=”true”>
<h:outputText value=”#{myVar}”>
</a4j:outputPanel>
</f:facet>
I hope this helps.
~David
March 15th, 2008 at 10:58 pm
David:
thanks! Working on Hugo’s advice what I ended up doing is this:
<rich:modalPanel id="pictureModal" autosized="true" zindex="2000"> <f:facet name="header"> <h:outputText id="pictureHeader" value="#{selectedImage.image.getDisplayHeading(100)}" /> </f:facet> ...and then my command link looks like this:
<a:commandLink id="showImage" action="#{selectedImage.setImage(image)}" oncomplete="Richfaces.showModalPanel('pictureModal',{width:760, top:200});" reRender="test,pictureHeader"> ...Which works great! But using an a4j output panel is a cool approach as well!
Thanks!
Devon
June 10th, 2008 at 8:56 am
I am new to JSF and had been trying to have a textbox in modalpanel which when typed should update the other textboxes in the same modalpanel. I have got sum examples in the http://livedemo.exadel.com/richfaces-demo/richfaces/support.jsf?c=support site and they seem to work perfectly. But when I place the same code in my modalPanel the server doesnt seem to understnad that there is indeed a textbox in the modalPanel. I am struggling with this for a day now and am running out of ideas. Any ideas or suggestions.
June 10th, 2008 at 8:59 am
@Chandra:
can you provide your code and the errors? Either post here or just e-mail them to me: devon@digitalsanctuary.com and I’ll be happy to take a look.
Devon
June 11th, 2008 at 8:49 am
Devon ,
I think I missed the most important point you have mentioned in your blog, that the modalPanel should be in a different jsp (or a diff form) than the parent jsp. I fixed it by creating a new JSP for the modalPanel.
Thanks
June 11th, 2008 at 11:06 am
@Chandra:
I’m glad to hear you have it working!
Devon
June 11th, 2008 at 2:37 pm
I am having other issue now. Not sure if its related to this blog but I hope someone could help me.
When I enter a value in one of the textboxes in my modalPanel, the other textboxes modalPanel needs to be updated.
I am writing a cutomtag to loop through my hashMap and get the values for the inputText.
my loop:index is the “key” for each loop.
HtmlInputText inputText = getHTMLInputTextObject(context,index, bean); HtmlAjaxSupport ajaxSupport = getAjaxSupport(context,index, bean); protected HtmlInputText getHTMLInputTextObject(FacesContext fc, String index, MyPresenceBean myPresence) { HtmlInputText inputText = new HtmlInputText(); inputText.setId(index); String value = (String) myPresence.getSelectedUoms(index).toString(); // gets the value for the key String bind = "#{serviceRegBean.myPresence.uoms[" + index + "]}"; //uoms is my hashMap inputText.setValueBinding("value", fc.getApplication().createValueBinding( bind)); inputText.setValue(value); return inputText; }This code doesnt call the onkeyUp event of the a4j support when I have a valueBinding in the InputText. So when I type in the textBox no event is called.
When I change the code for the getHTMLInputTextObject to
protected HtmlInputText getHTMLInputTextObject(FacesContext fc, String index, MyPresenceBean myPresence) { HtmlInputText inputText = new HtmlInputText(); inputText.setId(index); String value = (String) myPresence.getSelectedUoms(index).toString(); inputText.setValue(value); return inputText; }This seem to be working perfectly but I cant really bind the value to the bean this way.
Why doesnt the HTMLAJAXSupport event get called when we have ValueBinding for the inputtext? Hope I am making sense.
June 11th, 2008 at 4:21 pm
@Chandra:
Now you have me stumped:) I have no idea what to advise. Maybe someone else who reads this blog will..
Devon
June 12th, 2008 at 8:27 am
I think I found my way again with this. I created a collection of NameValuePairs and looping through them in the JSP with dataGrid.
But yeah in my 2 days with JSF, I have learned the tweaks.
Thanks..
June 15th, 2008 at 2:35 am
Gerson you save my life man!!! By your post, I could solve my disappointing problem with modal panes. wowww..
June 27th, 2008 at 3:21 pm
I am trying to use a modal panel wich has a lot of data to display… no matter what i try half of the panel is cut off the other half is below the page, I can drag it up to see everything. My only best guess is that it automatically centers the panel in the middle of the screen. This would be great if I only have a little bit of info. Does anyone know what I am doing wrong? How do I get it load in the position of the screen I want?
June 27th, 2008 at 3:31 pm
@Halley:
If the problem is that the modal is too big for the screen, this helps:
I put these two script tags near the bottom of my rich:modalPanel:
<script> document.getElementById('imageDisplayArea').style.height=f_clientHeight()-100+'px' </script> <script>document.body.onresize = function (){ document.getElementById('imageDisplayArea').style.height=f_clientHeight()-100+'px'}</script>just replace “imageDisplayArea” with a the main div containing the rich modal contents. This should set the modal panel size to be 100 pixels less than the client screen size, and should resize the modal when the user resizes their browser window (for browsers which throw a resize event).
If you want a scrollbar if the data is too big for the modal, you’ll want to set the style of that containing div to:
If the issue that it’s appearing too low on the page, but isn’t too small, you should be able to set the location it appears at when you call showModalPanel:
Richfaces.showModalPanel('pictureModal',{width:760, top:20});