Search code examples
xpages

Partial Refresh Repeat Control and Managed Bean running issue


I have a panel within an xPage set to partial refresh on a timer. As indicated by the Time fields the page outside the partial refresh panel does not refresh, however, a Managed Bean in a Repeat Control outside of the refresh panel initialises on each timer event. If I replace the Repeat Control with a ComputedField the Bean does not run. This is creating unnecessary load on the server as a lot of data is collected by the Managed Bean. The problem exist with a button event in addition to the timer.

The following is my test page. Any help is appreciated.

<xp:this.beforeRenderResponse><![CDATA[#{javascript:var time = new Date(); 
 var timeString=     ("0" + time.getHours()).slice(-2)   + ":" + 
("0" + time.getMinutes()).slice(-2) + ":" + 
("0" + time.getSeconds()).slice(-2);
viewScope.put("time",timeString)}]]></xp:this.beforeRenderResponse>

<xp:scriptBlock
id="scriptBlockRefresh">
<xp:this.value>
        <![CDATA[
            setInterval(function() 
            {XSP.partialRefreshGet("#{id:refreshPanel}", {})},
             10 * 1000);]]>
</xp:this.value>
</xp:scriptBlock>

<xp:panel  id="refreshPanel">
    <xp:text escape="true" value="#{classABean.classAText}"></xp:text>
    <xp:text escape="true" value="#{viewScope.time}"></xp:text>
</xp:panel>

<xp:panel id="restOfPagePanel">
<xp:text escape="true" id="computedField4" value="#{classBBean.classBText}"></xp:text>
<xp:repeat id="repeat1" rows="30" value="#{classBBean.classBText}" var="rowData">
    <xp:text escape="true"  value="#{rowData}"></xp:text>
</xp:repeat>
<xp:text escape="true" value="#{viewScope.time}"></xp:text>
</xp:panel>

Test Managed Beans

import java.io.Serializable;
public class ClassA implements Serializable{
private static final long serialVersionUID = 1L;
private String classAText;
public String getClassAText() {
    System.out.println("Running Class A");
    classAText = "I am Class A";
    return classAText;}

Same again for ClassB

FacesConfig

<managed-bean>
<managed-bean-name>classABean</managed-bean-name>
<managed-bean-class>uk.networkconnect.wallboardutils.ClassA</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>

 <managed-bean>
<managed-bean-name>classBBean</managed-bean-name>
<managed-bean-class>uk.networkconnect.wallboardutils.ClassB</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>

Button code used for testing.

 <xp:button value="Refresh Panel A" id="button1">
<xp:eventHandler event="onclick" submit="false" >
    <xp:this.script><![CDATA[XSP.partialRefreshGet("#{id:refreshPanel}",{})
            ]]></xp:this.script>
</xp:eventHandler>
</xp:button>

Solution

  • Your code should work but there's a catch - I can't say if you have already taken care of it or not. The fact is that with JSF you must make sure you load the data only the first time and be defensive about the subsequent calls. In fact, the engine might invoke the same method twice during the life cycle.

    By taking as example the mockup you provided the code should look like this:

    public class ClassA implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        private String text;
    
        public String getClassText() {
            if (text == null) {
                String name = getClass().getName();
    
                System.out.println("Running class " + name);
    
                text = "I am class " + name;
            }
    
            return text;
        }
    }
    

    Basically you set text only when it evaluates to null. Once the variable is set the code won't go inside the block anymore, no matter how many calls the engine makes to the method.

    The XPage doesn't need modification.

    <xp:scriptBlock
        value="
            setInterval(function() {
                XSP.partialRefreshGet('#{id:refreshPanel}');
            }, 10 * 1000)" />
    
    <xp:panel id="refreshPanel" style="background-color: red">
        <xp:text escape="true" value="#{a.classText}" />
        <xp:text escape="true" value="#{viewScope.time}" />
    </xp:panel>
    
    <xp:panel id="restOfPagePanel" style="background-color: grey">
        <xp:text escape="true" id="computedField4" value="#{b.classText}" />
    
        <xp:repeat id="repeat1" rows="30" value="#{b.classText}"
            var="rowData">
            <xp:text escape="true" value="#{rowData}" />
        </xp:repeat>
    
        <xp:text escape="true" value="#{viewScope.time}" />
    </xp:panel>
    
    <xp:button value="Label" id="button1">
        <xp:eventHandler event="onclick" submit="true"
            execMode="partial" refreshMode="partial" refreshId="refreshPanel" />
    </xp:button>