I’m making my first composite component in JSF but I am stumped by a rerender that behaves oddly. Here is the component implementation (it’s meant to be a popup):
<composite:implementation>
<h:outputScript name="nb-popup.js" library="js"/>
<h:outputStylesheet name="nb-popup.compiled.css" library="style"/>
<div id="#{cc.clientId}_container" class="nb_popup_container">
<div style="width:#{cc.attrs.width};height:#{cc.attrs.height};" id="#{cc.clientId}" class="nb_popup">
<div id="#{cc.clientId}_header" class="nb_popup_header">
<span class="nb_popup_header_content">
<composite:renderFacet name="header"/>
</span>
<span class="nb_popup_header_controls">
<composite:renderFacet name="controls"/>
</span>
</div>
<div id="#{cc.clientId}_content" class="nb_popup_content">
<composite:insertChildren/>
</div>
</div>
</div>
<script>popup('#{cc.clientId}');</script>
</composite:implementation>
For example let’s say we have:
<nb:popup id="extract">
test
</nb:popup>
The generated HTML is OK:
<div id="extract_container" class="nb_popup_container">
<div style="width:auto;height:auto;" id="extract" class="nb_popup">
<div id="extract_header" class="nb_popup_header">
<span class="nb_popup_header_content">
</span>
<span class="nb_popup_header_controls">
</span>
</div>
<div id="extract_content" class="nb_popup_content">
test
</div>
</div>
</div>
Now suppose I have a button:
<h:commandLink value="reload">
<f:ajax render=":extract"/>
</h:commandLink>
After pressing it, I get the following partial response where the actual content is clearly not where it’s supposed to be:
<div id="extract_container" class="nb_popup_container">
<div style="width:auto;height:auto;" id="extract" class="nb_popup">
<div id="extract_header" class="nb_popup_header">
<span class="nb_popup_header_content">
</span>
<span class="nb_popup_header_controls">
</span>
</div>
<div id="extract_content" class="nb_popup_content">
</div>
</div>
</div>
<script>popup('extract');</script>
test
]]>
Now suppose I move the insertChildren to the header:
<div id="#{cc.clientId}_header" class="nb_popup_header">
<span class="nb_popup_header_content">
<composite:renderFacet name="header"/>
<composite:insertChildren/>
</span>
<span class="nb_popup_header_controls">
<composite:renderFacet name="controls"/>
</span>
</div>
The initial load is again as it should be:
<div id="extract_header" class="nb_popup_header">
<span class="nb_popup_header_content">
test
</span>
<span class="nb_popup_header_controls">
</span>
</div>
But on reload the content is moved once again:
<div id="extract_header" class="nb_popup_header">
<span class="nb_popup_header_content">
</span>
<span class="nb_popup_header_controls">
test
</span>
</div>
Any idea what might be causing this seemingly random placement of the insertChildren after an ajax rerender?
As suggested by BalusC in a comment, wrapping the cc:insertChildren in a h:panelGroup seems to work. For example this works:
This allows me to retain the styling and js in the composite component (with the target=”head”) so overall it is a much better solution.
It’s a bug in Mojarra due to the outputStylesheet and outputScript tags. If you add target=”head” you get actual IndexOutOfBoundExceptions. Without the target it just does weird stuff on postbacks.
The current solution is to include the stylesheets and scripts in the main application. This partially negates easy reusability of the composite though.
Related open issues: