pakore
pakore

Reputation: 11497

modalPanel lazy rendering when displayed

Motivation: I want to reduce the size of the page when is accessed, so I thought that lazy rendering on modalPanels would help. The idea is to render the modalPanel when the user clicks the link that displays it.

I want to lazy render on rich:modalPanel when the link to display it is clicked. To achieve this I've found a way:

Code of the modalPanel, wrapped inside a a4j:outputPanel

 <a4j:outputPanel id="a4jPanel">
  <rich:modalPanel id="panel" rendered="#{bean.renderPanel}">
         <!-- here modalPanel things -->
  </rich:modalPanel>
 </a4j:outputPanel>

Code of the backing bean (session scope):

   public boolean isRenderPanel() {
   return renderPanel;   //default value is false;
   }

    public void setRenderPanel(boolean value){
           this.renderPanel=value;
    }

    public setRenderFalse(){
           this.setRenderPanel(false);
    }

Code of the page where it is invoked:

<a4j:form>
<a4j:jsFunction name="setRenderFalse" action="#{user.setRenderFalse}"/>
<a4j:commandLink value="render and show"  oncomplete="Richfaces.showModalPanel('panel');setRenderFalse();" reRender="a4jPanel">
<f:setPropertyActionListener target="#{user.renderPanel}" value="true" />
</a4j:commandLink>
</a4j:form>

Problems:

Any more elegant way to do this?

Upvotes: 7

Views: 6145

Answers (3)

Born78
Born78

Reputation: 95

Another solution is to set the render attribute of your modalpanel programmatically in the JSF component tree. So you wont't need an additional backing bean which has to handle one property to keep the state for each modalPanel:

Managed Bean:

public void togglePanel(ActionEvent event) {
    UIComponent component = event.getComponent();
    String forId = (String) component.getAttributes().get("for");

    FacesContext currentInstance = FacesContext.getCurrentInstance();
    UIComponent findComponent = ComponentFinder.findComponent(currentInstance.getViewRoot(), forId);
    findComponent.setRendered(!findComponent.isRendered());
}

View:

Open the panel:

<a4j:commandLink actionListener="#{myBean.togglePanel}" value="Open">
<f:attribute name="for" value="targetPanelId" />

Close the Panel:

<a4j:commandLink id="closePanel" actionListener="#{myBean.togglePanel}" value="someLabel">
<f:attribute name="for" value="targetPanelId" />

The modalpanel:

<a4j:outputPanel ajaxRendered="true">
        <rich:modalPanel id="targetPanelId" width="800" height="500" rendered="false" showWhenRendered="true">

Upvotes: 1

Maxim Manco
Maxim Manco

Reputation: 1944

There is a nice solution regarding your question. All is needed is a way to detect postback and couple of xhtmls.

First of all we need a bean that will help with indication of postback

public class HelperBean {

    public boolean isPostback() {
        FacesContext context = FacesContext.getCurrentInstance();
        return context.getRenderKit().getResponseStateManager().isPostback(context);
    }

}

empty.xhtml - for a blank content

<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:c="http://java.sun.com/jstl/core"
    xmlns:a4j="http://richfaces.org/a4j"
    xmlns:rich="http://richfaces.org/rich">

</ui:composition>

modal.xhtml - for wrapping the modal definition

<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:c="http://java.sun.com/jstl/core"
    xmlns:a4j="http://richfaces.org/a4j"
    xmlns:rich="http://richfaces.org/rich">

    <rich:modalPanel id="myLazyModal">
        <h:outputText value="Modal Content"/>
    </rich:modalPanel>
</ui:composition>

lazyModal.xhtml - for handling inclusion of the above xhtmls

<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:c="http://java.sun.com/jstl/core"
    xmlns:a4j="http://richfaces.org/a4j"
    xmlns:rich="http://richfaces.org/rich">

    <a4j:include id="lazyModal" layout="block"
        viewId="#{helperBean.postback ? 'modal.xhtml' : 'empty.xhtml'}"/>
</ui:composition>

finally use it

   <h:form id="frmTest">
        <a4j:include id="lazyModalContainer" layout="block" viewId="lazyModal.xhtml"/>
        <a4j:commandButton id="btnSubmit" value="Submit" reRender="lazyModalContainer"
            oncomplete="Richfaces.showModalPanel('myLazyModal');"/>
   </h:form>

Now when the page is loaded empty.xhtml will be included till btnSubmit is clicked.


Regarding to the problems you mentioned (1):

Re-rendering components with the rendered attribute is a bit catchy. When the rendered expression is evaluated to false no markup is sent back to the client. Therefore, supplying the id of the none rendered component to the reRender attribute will never work cause there is no such id on the client side (DOM).

Upvotes: 7

TaherT
TaherT

Reputation: 1335

i think you should make separate xhtml(facelet) of modal panel and use ui:include and than on link click the link no need of boolean property than.

enter code here : <ui:include src="modalPanel path">, <a4j:commandLink id="abclink" oncomplete="#{rich:component('yourPanelname')}.show()" reRender="yourPanelForm"/>

Upvotes: 1

Related Questions