Primefaces: Poll: IDs referenced in "update" are rerendered even though parent component is not rendered anymore

Created on 24 May 2021  路  3Comments  路  Source: primefaces/primefaces

Describe the defect
The component p:poll rerenders the components referenced in attribute "update", even though its parent component is not rendered anymore (which means p:poll is not rendered as well and so it should not be active).

Reproducer
Download the following project: https://drive.google.com/file/d/1OGOVhduAqnFO3uUcNi9UdneI-3Ls5wYP/view?usp=sharing.
Run: mvn jetty:run
Hit http://localhost:9999/primefaces-test to run the page.

Environment:

  • PF Version: 10.0.0
  • JSF + version: Mojarra 2.2.x
  • Affected browsers: tested in Chrome/Firefox

To Reproduce
Steps to reproduce the behavior:

  1. Go to 'http://localhost:9999/primefaces-test'.
  2. You will see a button and "Panel 1 rendered! Poll is active!".
  3. Wait for 30s and the "Counter:" should update (the value shown is incremented). You can see a message on browser console and in app logs that shows the listener being called.
  4. Click "Change active panel!".
  5. You'll see "Panel 2 rendered! Poll should not be active!".
  6. Wait for 30s and you'll see the "Counter:" is updated (unexpected behavior), even though p:poll is not rendered and listener is not called.

Expected behavior
The "Counter:" should not be updated after step 5.

The page has two panels that only one of them is rendered at a time. The first panel starts rendered and is the one that have p:poll defined. The other one does not have any p:poll. You can switch between them by clicking on button 'Change active panel!'. There is a "Counter:" that shows how many times this output text was rendered (update is called on it). The component p:poll defined calls a listener and updates this counter. This behavior is expected to work only when "Panel 1" is rendered. However, when "Panel 2" is rendered, the listener is not called, but we can see the "Counter:" is updated, which means the attribute "update" is being activated when p:poll is not rendered.

Example XHTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:p="http://primefaces.org/ui"
    xmlns:h="http://xmlns.jcp.org/jsf/html">

<h:head>
    <title>PrimeFaces Test</title>
    <h:outputScript name="test.js" />
</h:head>
<h:body>

    <p:growl>
        <p:autoUpdate />
    </p:growl>

    <h:form id="frmTest">

        <p:commandButton value="Change active panel!" update="@form" action="#{testView.changeActivePanel()}" />

        <br/>

        <p:outputPanel id="panel1" rendered="#{testView.renderPanel1}">
            <h:outputText value="Panel 1 rendered! Poll is active!" />
            <p:poll widgetVar="poll" interval="30" onstart="console.log(new Date().toISOString() + ': poll called!');" listener="#{testView.action()}" update="counter" />
        </p:outputPanel>

        <p:outputPanel id="panel2"  rendered="#{!testView.renderPanel1}">
            <h:outputText value="Panel 2 rendered! Poll should not be active!" />
        </p:outputPanel>

        <h:outputText id="counter" value="Counter: #{testView.retrieveCounter()}" />

    </h:form>

</h:body>
</html>

Example Bean

package org.primefaces.test;

import java.io.Serializable;
import java.time.LocalTime;

import javax.faces.view.ViewScoped;
import javax.inject.Named;

import lombok.Data;

@Data
@Named
@ViewScoped
public class TestView implements Serializable {

    private static final long serialVersionUID = 1L;

    private boolean renderPanel1 = true;

    private int counter = 0;

    public void changeActivePanel() {
        renderPanel1 = !renderPanel1;
    }

    public void action() {
        System.out.println(LocalTime.now() + ": listener called!");
    }

    public int retrieveCounter() {
        return ++counter;
    }
}
10.0.2 defect workaround

All 3 comments

@mertsincan @sqores marked as elite candidate, quite easy and good fix

If anyone else like me can't easily update PF version or wait for version 11, this is the workaround I'm using right now:

...
<p:outputPanel id="panel1" rendered="#{testView.renderPanel1}">
    <h:outputText value="Panel 1 rendered! Poll is active!" />
    <p:poll id="poll" widgetVar="poll" interval="30" onstart="console.log(new Date().toISOString() + ': poll called!');" listener="#{testView.action()}" update="counter" />
</p:outputPanel>

<script type="text/javascript">
    $(document).ready(function() {
        var widgetVarId = 'poll'; // UPDATE HERE! This must be the widgetVar of your poll. 
        var parentId = '#frmTest\\:panel1'; // UPDATE HERE! This must be a CSS Selector for the parent component ID that is rendered or not accordingly.
        var widget = PF(widgetVarId);
        if (!widget.cfg._originalFn) { // Safeguard
            var isActive = widget.active;
            if (isActive) {
                widget.stop();
            }
            widget.cfg._originalFn = widget.cfg.fn;
            widget.cfg.fn = function() {
                if ($(parentId).length) {
                    widget.cfg._originalFn();
                }
            }
            if (isActive) {
                widget.start();
            }
        }
    });
</script>
...

The solution is hardcoded for this specific scenario, but you can tweak for you own scenario (see comments "UPDATE HERE").
Once the poll is started, it is still kind of active when it is not rendered, although it does not call the listener and does not update the other elements.

Thanks for posting your workaround!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mertsincan picture mertsincan  路  3Comments

louayabdelhedi picture louayabdelhedi  路  3Comments

ghost picture ghost  路  3Comments

JoHoop picture JoHoop  路  3Comments

cnsgithub picture cnsgithub  路  4Comments