using insertChildren AND getting child attributes - jsf

I am actually trying to create a custom composite table component because h:datatable or p:datatable do not fit my needs. Nevertheless it shall be used like a primefaces datatable.
After I found JSF composite component childrens
and
Expose items of a list while iterating within composite component I saw the finish line, but now I got stuck.
My xhtml:
<h:body>
<sm:datatable mode="columntoggle" id="mytable" value="#{managerBean.objects}" var="object">
<sm:column header="KeyHeader" property="key">
<h:outputText value="#{object.key}"/>
</sm:column>
<sm:column header="ValueHeader" property="value">
<h:outputText value="#{object.value}"/>
</sm:column>
</sm:datatable>
</h:body>
And this is the datatable composite:
<cc:interface>
<cc:attribute name="id" />
<cc:attribute name="mode" />
<cc:attribute name="var" />
<cc:attribute name="value" type="java.util.List"/>
</cc:interface>
<cc:implementation>
<table data-role="table" data-mode="#{cc.attrs.mode}" id="my-table">
<thead>
<tr>
<ui:repeat value="#{component.getCompositeComponentParent(component).children}" var="child">
<th>
<h:outputText value="#{child.attrs.header}"/>
</th>
</ui:repeat>
</tr>
</thead>
<tbody>
<ui:repeat value="#{cc.attrs.value}" var="object">
<tr>
<c:forEach items="#{cc.children}" var="child" varStatus="loop">
<cc:insertChildren/>
</c:forEach>
</tr>
</ui:repeat>
</tbody>
</table>
</cc:implementation>
And that's the column composite
<cc:interface>
<cc:attribute name="header" />
<cc:attribute name="property" />
<cc:facet name="content"/>
</cc:interface>
<cc:implementation>
<td><cc:insertChildren/></td>
</cc:implementation>
thead works standalone
tbody works standalone
Putting them together like above I only get tbody. thead always stays empty Any suggestions?
Thanks for your help in Advance!

This is not a bug, it actually works as designed in mojarra. Using cc:insertChildren moves the children to the parent tag of the cc:insertChildren tag. This problem is equivalent to another problem and has the same solution. See my answer to this question.
Basically, you put a <ui:fragment> around the <cc:insertChildren>, bind that fragment to a property in a FacesComponent bean.

#{cc.children} which is equivalent to
#{component.getCompositeComponentParent(component).children} should both work
but for some reason fail to work in some versions , I guess this part of JSF is still little buggy .
Have you tried
#{cc.getFacets().get('javax.faces.component.COMPOSITE_FACET_NAME').children}
Please refer this thread as well,
In JSF2, how to know if composite component has children?

I was having the same issue. My workaround was to use a renderFacet, instead of insertChildren.
To iterate over the inserted elements I have used: #{cc.facets.yourFacetName.children} and to insert the elements themselves I have used: <composite:renderFacet name="yourFacetName"/>.

I've found iterating over children and using <composite:insertChildren /> in the same component to be near impossible. At least in the Mojarra 2.2.6 implementation.
The intermediate facet approach did not work for me either.
Eventually, my solution was to:
retain the child component (tab) as is
remove all code from the composite:implementation of parent (tab group) component
implement encodeAll() in the the faces component corresponding to parent
This question is over a year old. Please share if there's a simpler solution in sight.

Related

JSF 2.3 Facet in Composite Component with wrong ID

I have the following simple code in a composite component (using Mojarra 2.3.9 / Primefaces 7):
<composite:implementation>
<h:form id="form">
<composite:insertChildren />
<ui:fragment rendered="#{!empty cc.facets.actions}">
<div class="actions">
<composite:renderFacet name="actions" />
</div>
</ui:fragment>
</div>
</h:form>
</composite:implementation>
And the following part is used in a page, trying to fill the composite form with life:
<cc:compForm id="mySpecialForm">
<f:facet name="actions">
<p:commandButton
id="myBtn"
value="Submit"
process="#form"
update="#form">
</p:commandButton>
</f:facet>
</cc:compForm>
The form and all the children are rendered correctly and working quite well. But the button in the renderFacet block has - in my opinion - a wrong client ID, because instead of:
mySpecialForm:form:myBtn
the button only gets the following clientId:
mySpecialForm:myBtn
This leads to an error rendering the page:
Cannot find component for expression "#form" referenced from
"mySpecialForm:myBtn".:
org.primefaces.expression.ComponentNotFoundException: Cannot find
component for expression "#form" referenced from
"mySpecialForm:myBtn".
Am i doing something wrong or is this a bug in JSF/Primefaces? I also tried to configure the componentType to an #FacesComponent extending from UIForm, but in this case no form will be rendered at all.
Update 1:
I tried to create a "minimal, reproducible example (reprex)" like mentioned by Kukeltje. All what is needed are those 2 Parts in a web application (both files under resources):
cc/compForm.xhtml:
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:composite="http://xmlns.jcp.org/jsf/composite">
<composite:interface name="compForm" displayName="A composite form">
<composite:facet name="actions" />
</composite:interface>
<composite:implementation>
<h:form id="form">
<composite:insertChildren />
<composite:renderFacet name="actions" />
</h:form>
</composite:implementation>
</html>
compFormTest.xhtml:
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:cc="http://xmlns.jcp.org/jsf/composite/cc">
<cc:compForm id="mySpecialForm">
<h:inputText id="inputParam" value="" />
<f:facet name="actions">
<h:commandButton id="myBtn" value="Test" />
</f:facet>
</cc:compForm>
</html>
All todo is call the .xhtml page: http:localhost/YOUR_APP/compFormTest.xhtml.
After using it (at least with Mojarra JSF implementation), the input field has the following correct client ID mySpecialForm:form:inputParam. But the command button retrieves another client ID outside the form: mySpecialForm:myBtn, what is a bug from my point of view, regarding the JSF VDL: " ... will be rendered at this point in the composite component VDL view.".
But as i downstriped the example files, it is clearly not a primefaces problem, because the wrong client ID is also included, if using the standard h:commandButton component.
Perhaps someone can use the mentioned 2 files above in a MyFaces environment to check if the behaviour differs or is the same?
Or has someone a workaround in mind? Using an additional #FacesComponent and moving the button from facet to the right spot under the form leads to the following "funny" duplicate ID error:
"Cannot add the same component twice: mySpecialForm:form:myBtn" (at least the client ID was what i expected in the first place)

index of ui:repeat is empty [duplicate]

I have following code:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
However, when I open the page, it errors as follows:
component identifier must not be a zero-length String
But it is properly printed in the <h:outputText>. How is this caused and how can I solve it?
You can use EL in the id attribute of a JSF component, but the EL variable has to be available during view build time, while the JSF component tree is to be built. However, the <ui:repeat> runs during view render time, while the HTML output is to be generated based on JSF component tree. The <ui:repeat var> is not available during view build time and #{class2.name} evaluates to null which totally explains the error you got. That it works in <h:outputText> is because it runs during view render time.
If you replace <ui:repeat> by <c:forEach>, which runs during view build time, then it'll work as you intented. The <c:forEach> will namely generate physically multiple <h:form> components in the JSF component tree which each generate individually their own HTML output (in contrary to <ui:repeat>, wherein the very same <h:form> component is been reused multiple times to generate HTML output).
<c:forEach var="class2" items="#{bean.list}" varStatus="status">
<h:form id="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</c:forEach>
However, I really wonder why you need to do that. There's usually no need to dynamically assign component IDs. JSF will already ensure the uniqueness of the ID. The below example,
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="form">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
will end up in multiple forms with each an unique ID, suffixed with iteration index of the <ui:repeat>. If you actually need to use #{class2.name} for some JavaScript/jQuery purposes (you did nowhere state the concrete functional requirement in the question for which you thought that this would be the right solution, so it's merely guessing), then just wrap it in a plain vanilla HTML element:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<div id="#{class2.name}">
<h:form id="form">
<h:outputText value="#{class2.name}" />
</h:form>
</div>
</ui:repeat>
Or set it as style class of a JSF component, which is also just selectable via a CSS selector:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="form" styleClass="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
See also:
JSTL in JSF2 Facelets... makes sense?

How concat with JSF code in id attribute on XHTML? [duplicate]

I have following code:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
However, when I open the page, it errors as follows:
component identifier must not be a zero-length String
But it is properly printed in the <h:outputText>. How is this caused and how can I solve it?
You can use EL in the id attribute of a JSF component, but the EL variable has to be available during view build time, while the JSF component tree is to be built. However, the <ui:repeat> runs during view render time, while the HTML output is to be generated based on JSF component tree. The <ui:repeat var> is not available during view build time and #{class2.name} evaluates to null which totally explains the error you got. That it works in <h:outputText> is because it runs during view render time.
If you replace <ui:repeat> by <c:forEach>, which runs during view build time, then it'll work as you intented. The <c:forEach> will namely generate physically multiple <h:form> components in the JSF component tree which each generate individually their own HTML output (in contrary to <ui:repeat>, wherein the very same <h:form> component is been reused multiple times to generate HTML output).
<c:forEach var="class2" items="#{bean.list}" varStatus="status">
<h:form id="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</c:forEach>
However, I really wonder why you need to do that. There's usually no need to dynamically assign component IDs. JSF will already ensure the uniqueness of the ID. The below example,
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="form">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
will end up in multiple forms with each an unique ID, suffixed with iteration index of the <ui:repeat>. If you actually need to use #{class2.name} for some JavaScript/jQuery purposes (you did nowhere state the concrete functional requirement in the question for which you thought that this would be the right solution, so it's merely guessing), then just wrap it in a plain vanilla HTML element:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<div id="#{class2.name}">
<h:form id="form">
<h:outputText value="#{class2.name}" />
</h:form>
</div>
</ui:repeat>
Or set it as style class of a JSF component, which is also just selectable via a CSS selector:
<ui:repeat var="class2" value="#{bean.list}" varStatus="status">
<h:form id="form" styleClass="#{class2.name}">
<h:outputText value="#{class2.name}" />
</h:form>
</ui:repeat>
See also:
JSTL in JSF2 Facelets... makes sense?

Dynamic 2D arrayList table not working after refreshing in primefaces?

I am using prime-faces 5 and jsf, I've created dynamic 2D arraylist table based on Tester and Date, first time its showing values correctly with date. But next time onwards its showing different tester name in single row.
The above showing first row correctly showing tester name but 2nd and 3rd showing different values. But i want to display same tester name in each row level.
MY XHTML:
<div align="left" class="width100">
<div class="DTHeader">
<h:form id="frmres">
<h:panelGrid columns="2"
style="padding-top:35px;padding-left:30px;">
<h:outputText class="lighttxt1" value="Schedule Date" />
<p:calendar id="button" value="#{schedulerbean.sch.scheDate}"
styleClass="cal schdate" label="Schedule Date" showOn="button"
pattern="dd/MM/yyyy HH:mm" showButtonPanel="true"
required="true">
</p:calendar>
<h:outputText value="TCU Goal" class="lighttxt1" />
<h:panelGrid columns="1" >
<p:inputText id="tcu" label="The Value given in TCU is"
style="border: 1px solid #A8A8A8 !important;background: transparent !important;"
styleClass="txtbig" value="#{schedulerbean.sch.tcu}"
keypadOnly="true" required="#{tcselectionbean.mancnt} != 0}" />
<h:outputText value="(Total Tcu:#{schedulerbean.tottalTCU})" class="lighttxt1" />
</h:panelGrid>
<h:outputText value="Select Squad" styleClass="txtblack14" />
<p:selectOneMenu value="#{schedulerbean.sch.squadparam}"
panelStyleClass="panel" styleClass="DTDD ddwidth1">
<f:selectItem itemLabel="All Tester" itemValue=""
styleClass="txtblack14" />
<f:selectItems value="#{schedulerbean.squadLst}" var="squadval"
itemLabel="#{squadval}" itemValue="#{squadval}"
styleClass="txtblack14" />
</p:selectOneMenu>
</h:panelGrid>
<h:panelGrid columns="1">
<p:commandButton
actionListener="#{schedulerbean.resourcePlanWithPossibleEnddate}"
value="Calculate" styleClass="blubtn"
update=":frmres:reservtable" />
<h:panelGroup id="reservtable">
<table class="bor bortd" style="margin-left:32px;">
<thead>
<tr>
<th>Tester Name / Dates</th>
<c:forEach var="resdate" items="#{schedulerbean.resDateList}">
<th>#{resdate}</th>
</c:forEach>
</tr>
</thead>
<c:forEach var="reserv" items="#{schedulerbean.resList}">
<tr>
<td>
<h:selectBooleanCheckbox value="#{schedulerbean.testerCheckboxmap[reserv.testerName]}"
styleClass="lighttxt1" />#{reserv.testerName}</td>
<c:forEach var="resdate1" items="#{schedulerbean.resDateList}">
<td class='c#{reserv.reserveType.get(resdate1)}'>
#{reserv.testerName} #{reserv.tcuMap.get(resdate1)}</td>
</c:forEach>
</tr>
</c:forEach>
</table>
</h:panelGroup></h:panelGrid>
<p:commandLink styleClass="bluelinknew"
action="#{schedulerbean.setSchedulestep('step3')}"
update=":schmenufrm" value="Next" style="float:right;"
onclick="javascript:changets('schedule');" />
</h:form>
</div>
</div>
How can i achieve this?
You are misusing the forEach JSTL tag. The tag is only in effect when the component tree is built, and the component tree is not re-built for post-backs and AJAX requests.
bwright's suggestion to use a <p:dataTable> is good, but you could also use <ui:repeat> if you don't want to render an HTML table.
https://rogerkeays.com/jsf-c-foreach-vs-ui-repeat
The most important thing to understand about the JSTL tags in JSF is
that they do not represent components and never become a part of the
component tree once the view has been built. Rather, they are tags
which are actually responsible for building the tree in the first
place. Once they have done their job they expire, are no more, cease
to be, etc etc.
...
When is the view built?
Now that you understand that tag handlers are only effective when the
tree is built, the next logical question should be well, when is tree
built?
The short answer is that a new view is built for every request which
is not a postback. During a postback, the view is reconstructed from
saved state. Quite confusing, and not very obvious I know, but there
you have it.
...
My list doesn't change size after deleting or adding an item
When your view was built you only had, say, 5 items. If you post back
to this view and add or delete an item, your view still has 5
h:outputText components in it since it was restored from saved state.
In this simple case, you should use ui:repeat and your tree will
always contain one h:ouputText component which is iterated over with
differing values of ${item}.
If you rely on using c:forEach to dynamically include different form
components you could run into difficulty. Always try to think about
what the resulting tree looks like and remember it doesn't change on a
postback.
See also
https://rogerkeays.com/jsf-c-foreach-vs-ui-repeat (quoted above)
JSTL in JSF2 Facelets... makes sense?

how to remove worthless tags from jsf f:selectItem

I will create a list with checkbox. Anything like gmail mail box. I use h:selectManyCheckbox , f:selectItem in HTML table tag. But jsf tags, itselft create a table and destruct my form. How can id say to jsf tags that just create input tag not anymore?
the following is a peace of my code:
<tbody>
<h:selectManyCheckbox value="#{MemberControl.selectedUser}">
<c:forEach items="#{MemberSearchControl.members}" var="member" varStatus="status">
<tr>
<td><f:selectItem itemValue="#{member.id}"></f:selectItem> </td>
<td><span>#{member.lastName}</span></td>
<td><span>#{member.firstName}</span></td>
<td><span>#{member.shareCount}</span></td>
<td><span>#{member.phone}</span></td>
</tr>
</c:forEach>
</h:selectManyCheckbox>
</tbody>
And in the following you can see the result:
Do you have any solution for move checkbox in its correct place? (I use pure jsf not primefaces or any more)
Thanks.
This behavior is as documented. Your attempt to fix this makes absolutely no sense. The <c:forEach><f:selectItem> should just be a <f:selectItems> and you should be using a custom renderer for the job. Tomahawk has already done it before for you, its <t:selectManyCheckbox> with layout="spread" attribute set, along with <t:checkbox> components declared at the desired places, allows you to control the markup fully:
<!-- This piece renders _nothing_. -->
<t:selectManyCheckbox id="foo" value="#{bean.selectedItems}" layout="spread">
<f:selectItems value="#{bean.availableItems}" />
</t:selectManyCheckbox>
<!-- You can markup those the way you want. They solely render <input>. -->
<t:checkbox for="foo" index="0" />
<t:checkbox for="foo" index="1" />
<t:checkbox for="foo" index="2" />
<t:checkbox for="foo" index="3" />
...
An alternative is to just fix your CSS styles. It look too much like that you overgeneralized table, tr, td, etc styles to be applied on all of those elements instead of only those by a specific style class such as table.datatable for <h:dataTable styleClass="datatable">.

Resources