0 Replies Latest reply on Dec 3, 2007 10:23 AM by Jonck van der Kogel

    Dynamically creating modal panels

    Jonck van der Kogel Newbie

      Hi,
      We are encountering a difficult problem at the moment. Recently we decided to move from RichFaces 3.0.1 to RichFaces 3.1.2.SP1. This has caused our use of the rich:modalPanel component to stop functioning however.

      Here is how we used to do it: we created a facelet that contains the rich:modalPanel tag (some irrelevant parts snipped):

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml"
       xmlns:ui="http://java.sun.com/jsf/facelets"
       xmlns:h="http://java.sun.com/jsf/html"
       xmlns:f="http://java.sun.com/jsf/core"
       xmlns:c="http://java.sun.com/jstl/core"
       xmlns:t="http://myfaces.apache.org/tomahawk"
       xmlns:holmes="http://vrom.nl/holmes"
       xmlns:a4j="https://ajax4jsf.dev.java.net/ajax"
       xmlns:rich="http://richfaces.ajax4jsf.org/rich">
      
      <ui:composition>
       <h:panelGroup>
       <c:set var="a4jOutputPanelId" value="#{id}_a4jOutputPanelId" />
      
       <h:panelGroup id="#{id}_panelGroup">
       <a4j:region id="#{id}_region" renderRegionOnly="false">
      
       <a4j:commandButton id="#{id}_zoeken_button" reRender="#{id}_zoeken"
       rendered="#{rendered}" value="#{label}"
       onclick="Richfaces.showModalPanel('#{id}_mp')" styleClass="knop"
       disabled="#{disabled}">
       <f:setPropertyActionListener value="#{true}"
       target="#{modalPanelController[renderedField]}" />
       <ui:insert />
       </a4j:commandButton>
      
       <div class="#{id}_container">
       <rich:modalPanel id="#{id}_mp"
       height="600" top="20" left="112" width="900" resizeable="true"
       moveable="true">
       <f:facet name="header">
       <h:outputText value="#{title}" />
       </f:facet>
       <h:panelGroup id="#{id}_zoeken">
       <h:panelGroup rendered="#{modalPanelController[renderedField]}">
       <div class="content">
       <a4j:outputPanel id="#{a4jOutputPanelId}">
       <a4j:include viewId="#{uri}" />
       </a4j:outputPanel>
       </div>
       </h:panelGroup>
       </h:panelGroup>
       </rich:modalPanel>
       </div>
       </a4j:region>
       </h:panelGroup>
       </h:panelGroup>
      </ui:composition>
      </html>
      


      This enabled us to put buttons in our views that would pop open a modal panel with whatever content we passed as viewId uri. This worked great. However, with the new version of RichFaces it is no longer allowed to have a form within a form. If you want to submit values from the modal panel we need the modal panel to contain a form. And also since we are using the facelet setup, this means we will always have a form within a form.

      Therefore our old facelet setup is no longer functioning. We then figured we could programatically create the modal panels when needed. While doing some experimentation I came up with the following:
      In the view I put this:
      <h:commandButton id="testModalPanel" value="test"
       action="#{modalPanelController.createModalPanel}">
       <h:panelGroup rendered="false" id="test123">
       <a4j:outputPanel>
       <a4j:include viewId="/zoeken/zoekLocatiePopup.xhtml" />
       </a4j:outputPanel>
       </h:panelGroup>
       <f:actionListener type="org.vrom.vi.dpvi.holmes.web.controller.generic.ModalPanelController" />
      </h:commandButton>
      


      And in the backing bean:
      private final static String CALLER_CHILD = "callerCHild";
      
      public void processAction(ActionEvent ae) throws AbortProcessingException {
       UIComponent caller = ae.getComponent();
       HttpSession session = FacesUtils.getHttpServletRequest().getSession();
      
       UIComponent callerChild = null;
       for (UIComponent child : caller.getChildren()) {
       System.out.println("Component id: " + child.getId());
       System.out.println("Component class: " + child.getClass());
       callerChild = child;
       }
       caller.getChildren().remove(callerChild);
      
       session.setAttribute(CALLER_CHILD, callerChild);
      }
      
      public String createModalPanel() {
       HttpSession session = FacesUtils.getHttpServletRequest().getSession();
       UIComponent callerChild = (UIComponent) session.getAttribute(CALLER_CHILD);
       FacesContext context = FacesContext.getCurrentInstance();
       Application app = context.getApplication();
       UIViewRoot view = context.getViewRoot();
      
       HtmlModalPanel myPanel = (HtmlModalPanel) app.createComponent(HtmlModalPanel.COMPONENT_TYPE);
       HtmlOutputText outputText = new HtmlOutputText();
       outputText.setValue("test");
       myPanel.getFacets().put("header", outputText);
      
       myPanel.getChildren().add(callerChild);
       callerChild.setParent(myPanel);
      
       myPanel.setMoveable(true);
       myPanel.setResizeable(true);
       myPanel.setId("uniqueMpId");
       myPanel.setWidth(600);
       myPanel.setHeight(600);
       myPanel.setTop("100");
       myPanel.setLeft("100");
       myPanel.setRendered(true);
       myPanel.setShowWhenRendered(true);
      
       UIComponent baseForm = view.findComponent("myForm");
       baseForm.getChildren().add(myPanel);
      
       return "testerdetest";
      }
      


      As you can see, what we're trying to do is attach the view to the button that calls the createModalPanel method. Using an actionlistener, the UIComponent child of the h:commandButton is put on the session (just for testing) and removed as a child from that h:commandButton. In the action method we then create the modal panel and add the UIComponent that we put on the session earlier to the modal panel.

      Everything seems to be working except the child of the h:commandButton is not being removed, causing duplicateID errors to be thrown.

      Basically what I want to achieve here is to be able to create rich:modalPanel components at run-time and passing on as an argument which view (xhtml) should be shown inside the modal panel.

      At this point I am stuck, out of ideas. Could someone please help me out with this?

      Thanks very much, Jonck