The premise is quite straightforward: I have a page layout that relies on nested composite components (CC) to do the rendering, i.e. one JSF page references a CC, which itself references another CC, which contains a call to a third CC. - Source below.
Now, when that third CC wants to execute a bean method using ajax which would result in a fully self-contained partial update... nothing happens.*
I have searched SO and other places extensively, and have investigated all points of BalusC's insightful post here, but I've come up empty. Trace logging finally turned up the following message during the apply, validate and render stages, resulting in an "empty" response: FINER [javax.enterprise.resource.webcontainer.jsf.context] ... JSF1098: The following clientIds were not visited after a partial traversal: fooForm:j_idt14:j_idt15:j_idt18 . This is a waste of processor time and could be due to an error in the VDL page.
*) This only happens under very particular circumstances (which, though, are the exact definition of my use case):
- Deeply nested CCs, at least two parent levels.
- The nesting must be implicit, i.e. different CCs calling another, not just nested tags directly inside the calling page.
- "Higher" CCs pass down children which are inserted in the "lower" CC using
<cc:insertChildren />
. - The CC that performs the ajax call and partial update contains
actions
dynamically created from the CC's attributes or clientId. (But not even necessarily in the same call, just inside the same component.)
All have to be met at the same time: If I use the innermost CC higher up in the hierarchy (or the nesting including the call to the final CC is all inside the calling page), everything works. If I use facets, no problem. If I remove or hard-code the action
parameter, all good.
(Currently testing on EE6, EAP 6.4, but is the same in an EE7 project running on EAP 7.0)
Calling page:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:my="http://java.sun.com/jsf/composite/components/nestedcomponents">
<h:head>
<title>Nested composite component test</title>
</h:head>
<h:body>
<h:form id="fooForm">
<h2>Works</h2>
<my:randomString saveBean="#{util}" saveAction="doSomething" />
<h2>Doesn't</h2>
<my:containerInsertingAnotherUsingInsertChildren>
<my:randomString saveBean="#{util}" saveAction="doSomething" />
</my:containerInsertingAnotherUsingInsertChildren>
</h:form>
</h:body>
</html>
Innermost CC: (<my:randomString>
, black frame; the #{util}
is a request-scoped bean with one-liner dummy methods)
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<cc:interface>
<cc:attribute name="someValue" />
<!--cc:attribute name="someAction" method-signature="void action()" /-->
<!--cc:attribute name="someAction" targets="btn" targetAttributeName="action" /-->
<cc:attribute name="saveBean" />
<cc:attribute name="saveAction" />
</cc:interface>
<cc:implementation>
<h:panelGroup layout="block" id="box" style="border: 1px solid black; margin: 3px; padding: 3px;">
<h:outputText value="#{cc.attrs.id} / #{cc.clientId} / #{util.getRandomString()} " />
<h:commandLink id="btn" value="save!" action="#{cc.attrs.saveBean[cc.attrs.saveAction]}" >
<f:ajax render="box" immediate="true" />
</h:commandLink>
</h:panelGroup>
</cc:implementation>
</html>
Outer, wrapping CC: (<my:containerInsertingAnotherUsingInsertChildren>
, red frame)
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:my="http://java.sun.com/jsf/composite/components/nestedcomponents">
<cc:interface>
</cc:interface>
<cc:implementation>
<h:panelGroup layout="block" style="border: 1px solid red; margin: 3px; padding: 3px;">
<my:containerUsingInsertChildren>
<cc:insertChildren />
</my:containerUsingInsertChildren>
</h:panelGroup>
</cc:implementation>
</html>
Intermediate CC: (<my:containerUsingInsertChildren>
, blue frame)
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<cc:interface>
</cc:interface>
<cc:implementation>
<h:panelGroup layout="block" style="border: 1px solid blue; margin: 3px; padding: 3px;">
<cc:insertChildren />
</h:panelGroup>
</cc:implementation>
</html>
As I wrote, hard-coded calls work as expected and update the little attached box. As soon as the bean method involves parameters (attributes) of the CC, and the CC sits deep enough in the hierarchy, they just get skipped.
I'm at a loss, and solutions or workarounds are most welcome.