0

I am trying to insert a popup which has to be lazy-loaded when clicking a h:commandButton. I insert its content via ui:include. However the preRenderView method is not being fired and the PopupPageModel model property is not being initialized so I get a NullPointerException when trying to invoke the business logic method inside PopupPageController.

The idea is having separate Model/Controller beans for both pages involved but I am not sure this is the correct approach, so I would like to know other approaches or the correct way to implement mine.

Thanks in advance.

Invoking page:

<h:commandButton
value="#{msg['jsf.thisScreen.someText']}">
  <f:param name="theParameter" value="#{InvokingScreenModel.theParameter}" />
  <rich:componentControl target="myPopup" operation="show" />
</h:commandButton>

<rich:popupPanel id="myPopup" modal="true" resizeable="false" autosized="true"
   onmaskclick="#{rich:component('myPopup')}.hide()">
   <f:facet name="header">
      <h:outputText value="#{msg['jsf.anotherScreen.someText']}" />
   </f:facet>
   <f:facet name="controls">
      <h:outputLink value="#" onclick="#{rich:component('myPopup')}.hide(); return false;"></h:outputLink>
   </f:facet>
   <ui:include src="popupPage.xhtml" />
</rich:popupPanel>

Popup page:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    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"
    xmlns:c="http://java.sun.com/jsf/core">


    <f:metadata>
        <f:viewParam name="theParameter"
                    value="#{PopupPageModel.theParameter}" />
        <f:event type="preRenderView"
                    listener="#{PopupPageController.initialize}" />
    </f:metadata>


    <h:form id="someForm">
       //Some things here
    </h:form>
</ui:composition>

Popup page controller

@Component("PopupPageController")
@Scope("request")
public class PopupPageController {

    @Autowired
    private PopupPageModel model;
    @Autowired
    private SomeService service;

    public void initialize(){       
        if (!FacesContext.getCurrentInstance().isPostback()) {
            //Change some model properties via service methods
        }
    }

    public void doSomething() {

    }

}
jplatasv
  • 155
  • 3
  • 18
  • Refer to the `f:metadata` [vld](http://docs.oracle.com/javaee/7/javaserverfaces/2.2/vdldocs/facelets/f/metadata.html), which says: "This tag must reside within the top level XHTML file for the given viewId, or in a template client, but not in a template." Which explains why your event doesn't fire. As for your architecture: need to call on a spring expert here, no idea how that works outside of normal JSF/CDI. – mabi Feb 11 '14 at 13:41
  • Thanks for your answer, @mabi. I was suspecting that my usage of the `f:metadata` tag was not correct. I am thinking that I also should change the architecture but I am not sure. Let's see if somebody else answers :) – jplatasv Feb 11 '14 at 14:07

1 Answers1

0

I've been struggling with this for several days and I've been unable to find a lazy-loading solution for the popup so I'm posting a solution I managed to do that doesn't include this feature just in case it's useful for someone.

Invoking page extract

<h:form>
    <a4j:outputPanel id="stuffDetails">
        //Some ajax-rendered tabs and accordions above the button
        .....
        .....
        
        <a4j:commandButton
            value="Open Popup"
            actionListener="#{PopupController.someInitializationListenerMethod}"
            oncomplete="#{rich:component('thePopup')}.show();"
            render="formPopup">
        </a4j:commandButton>
    </a4j:outputPanel>
</h:form>

<rich:popupPanel id="thePopup" modal="true"
    resizeable="false" autosized="true"
    onmaskclick="#{rich:component('thePopup')}.hide();">
    <f:facet name="header">
        <h:outputText value="Some header here" />
    </f:facet>
    <f:facet name="controls">
        <h:outputLink value="#"
            onclick="#{rich:component('thePopup')}.hide(); return false;">
        </h:outputLink>
    </f:facet>
    <h:form id="formPopup">
        <ui:include src="popup.xhtml" />
    </h:form>
</rich:popupPanel>

popup.xhtml

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
<html>

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    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"
    xmlns:c="http://java.sun.com/jsf/core">

    //Some controls shown inside the popup
    ......
    ......
    
    <a4j:commandButton value="Process data and close popup"
        actionListener="#{PopupController.someProcessingMethod}"
        render=":stuffDetails :formPopup"
        oncomplete="#{rich:component('thePopup')}.hide();" />
    <h:commandButton value="Cancel"
        onclick="#{rich:component('thePopup')}.hide(); return false;" />

</ui:composition>

</html>

The render=":stuffDetails :formPopup" in popup.xhtml is to avoid the infamous JSF spec issue 790 described by BalusC here and here.

Any suggestions welcome.

Emil Sierżęga
  • 1,785
  • 2
  • 31
  • 38
jplatasv
  • 155
  • 3
  • 18