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:
To Reproduce
Steps to reproduce the behavior:
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;
}
}
@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!