Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

modalPanel lazy rendering when displayed

Tags:

jsf

richfaces

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:

  • The modalPanel needs to be wrapped inside an a4j:outputPanel because reRendering directly the modalPanel does not work (I never understood why).

  • After rendering it, an extra request is needed to set the render value to false (the bean is session scoped). Otherwise if we reload the page there would not be any lazy rendering because the value was set to true.

  • The backing bean has to handle one property to keep the state for each modalPanel, although this property is set to true whenever the link is clicked and set to false when the request is finished. I've tried to keep the rendered state with JS variables but it does not seem to work (they are just read once the page is loaded and never again).

Any more elegant way to do this?

like image 488
pakore Avatar asked Jul 07 '10 10:07

pakore


3 Answers

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).

like image 135
Maxim Manco Avatar answered Nov 06 '22 12:11

Maxim Manco


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"/>
like image 25
2 revs Avatar answered Nov 06 '22 12:11

2 revs


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">
like image 43
Born78 Avatar answered Nov 06 '22 12:11

Born78