Предпосылка довольно проста: у меня есть макет страницы, который использует вложенные составные компоненты (CC) для выполнения рендеринга, то есть одна страница JSF ссылается на CC, который сам ссылается на другой CC, который содержит вызов третьего CC. - Источник ниже.
Теперь, когда этот третий CC хочет выполнить метод компонента с использованием ajax, что приведет к полностью автономному частичному обновлению... ничего не происходит.*
Я тщательно искал SO и другие места и исследовал все точки проницательного поста BalusC здесь, но я придумал пустой. В конце концов, ведение журнала трассировки обнаружило следующее сообщение на этапах применения, проверки и рендеринга, что привело к «пустому» ответу: FINER [javax.enterprise.resource.webcontainer.jsf.context] ... JSF1098: следующие clientIds не были посещены после частичного обхода: fooForm:j_idt14:j_idt15:j_idt18 . Это пустая трата процессорного времени, которая может быть вызвана ошибкой на странице VDL.
*) Это происходит только при очень специфических обстоятельствах (которые, тем не менее, являются точным определением моего варианта использования):
- Глубоко вложенные CC, как минимум два родительских уровня.
- Вложение должно быть неявным, т. е. разные CC вызывают другой, а не просто вложенные теги непосредственно внутри вызывающей страницы.
- «Высшие» CC передают потомков, которые вставляются в «нижний» CC с помощью
<cc:insertChildren />
. - CC, который выполняет вызов ajax и частичное обновление, содержит
actions
, динамически создаваемых из атрибутов CC или clientId. (Но даже не обязательно в том же вызове, просто внутри одного и того же компонента.)
Все они должны выполняться одновременно: если я использую самый внутренний CC выше в иерархии (или вложение, включая вызов последнего CC, находится внутри вызывающей страницы), все работает. Если я использую фасеты, нет проблем. Если я удалю или жестко запрограммирую параметр action
, все будет хорошо.
(В настоящее время тестируется на EE6, EAP 6.4, но то же самое в проекте EE7, работающем на EAP 7.0)
Страница вызова:
<!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>
Самый внутренний CC: (<my:randomString>
, черная рамка; #{util}
— это bean-компонент с областью запроса и однострочными фиктивными методами)
<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>
Внешний, упаковка CC: (<my:containerInsertingAnotherUsingInsertChildren>
, красная рамка)
<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>
Промежуточный CC: (<my:containerUsingInsertChildren>
, синяя рамка)
<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>
Как я уже писал, жестко закодированные вызовы работают как положено и обновляют маленькую прикрепленную коробочку. Как только bean-метод включает параметры (атрибуты) CC, а CC находится достаточно глубоко в иерархии, они просто пропускаются.
Я в недоумении, и решения или обходные пути приветствуются.