Recursion with include and h:datatable [duplicate] - jsf

This question already has an answer here:
JSTL c:if doesn't work inside a JSF h:dataTable
(1 answer)
Closed 7 years ago.
I'm having some troubles trying to recursively include pages. The problem is that all the include actually take place but there is something going on with the h:dataTable that makes it so the second included datatable content isn't displayed.. I'm guessing the problem comes from the var post being concurrent with itself. It works without the datatable.
So from a page.xhtml I'm calling an include for post_view2.xhtml:
<ui:include src="/template/includes/post_view2.xhtml" >
<ui:param name="postList" value="#{watchThread.listeFirstPosts}"></ui:param>
<ui:param name="count" value="8"></ui:param>
</ui:include>
Count is set to 8.
This is post_view2.xhtml:
<ui:composition xmlns=....>
<h:dataTable var="post" value="#{postList}" styleClass="fullWidth">
<h:column>
#{post.posts.size()} <!-- gives a size higher than 0 -->
<h:outputText value="#{watchThread.sanitize(post.content)}"/>
<c:if test="${count gt 0}">
<ui:include src="/template/includes/post_view2.xhtml">
<ui:param name="postList" value="#{post.replies}"></ui:param>
<ui:param name="count" value="${count-1}"></ui:param>
</ui:include>
</c:if>
</h:column>
</h:dataTable>
</ui:composition>
Notice that at the first include the post var is equal to a list. On the second include I'm trying to make it equal to another list and I think that is what is causing the problem. I don't know why nor how to solve it.
On a side note I'm using jstl c:if but if there is another solution that is pure jsf, primefaces included I'd take it.

I found a bit of a workaround but I'll let the question as unanswered.
Instead of using DataTable I'm using jsp tag forEach and it works.
so instead of this:
<h:dataTable var="post" value="#{postList}">
I have :
<c:forEach var="post" items="#{postList}">
I don't know why this works and dataTable doesn't. If anyone knows please expand.

Related

jsf set ui:param or use a value that changes dynamically in ui:repeat

I want to update an ui:param value or use something similar in ui:repeat loops with a condition. The idea is something as follows (is just an aprox, not the final implementation but I guess is understandable):
<ui:param name="marginLeftNode" value="#{myBean.initialMarginValue}" />
<ui:repeat value="#{myBean.viewWrapper.linkMap.entrySet().toArray()}" var="map">
<ui:repeat var="link" value="#{map.value}" varStatus="status">
<li style="margin-left: #{marginLeftNode}%" class="ico-#{link.getStyleCss()}-ayuda">
#{link.getTitle()}
</li>
<!-- Code conditions that doesn't works in any way as I've readed in the links after code -->
<c:if test="#{marginLeftNode gt 4}">
<ui:param name="marginLeftNode" value="#{myBean.viewWrapper.nodeList.get(status.index).depth}" />
</c:if>
<ui:fragment rendered="#{marginLeftNode gt 4}">
<ui:param name="marginLeftNode" value="#{myBean.viewWrapper.nodeList.get(status.index).depth}" />
</ui:fragment>
<!-- End code conditions: these are the two solutions c:if and ui:fragmen I tried -->
</ui:repeat>
</ui:repeat>
I can't use c:if inside ui:repeat because doesn't works (Specify conditional rendering of element inside <ui:repeat>? The <c:if> does not seem to work) and I can't use ui:fragment with ui:param because it doesn't works too (Conditional variable definition in JSF)
So, any idea how to solve that?
First of all, avoid of use JSTL if you can use JSF. Here is an answer that explains how JSTL and JSF are executed in different steps -> https://stackoverflow.com/a/3343681/4253629
To redefine conditionally a ui:param, for example, you can do this:
<ui:param
name="marginLeftNode"
value="#{marginLeftNode gt 4 ? myBean.viewWrapper.nodeList.get(status.index).depth : marginLeftNode }"/>
Probably exists another solution, but this works.
Greetings
Changing the ui:param inside the loop has no real value. The real purpose of a ui:param is to pass runtime variables into a template client or included file. By the time your parameter has been passed in, there's little value in changing it. If all you want is to conditionally alter the value of the variable after it's been passed, you could just use JSTL's c:set to set a page-scoped variable that you could then use
<ui:repeat value="#{myBean.viewWrapper.linkMap.entrySet().toArray()}" var="map">
<ui:repeat var="link" value="#{map.value}" varStatus="status">
<li style="margin-left: #{marginLeftNode}%" class="ico-#{link.getStyleCss()}-ayuda">
#{link.getTitle()}
</li>
<c:if test="#{marginLeftNode gt 4}">
<c:set var="marginLeftNode" value="#{myBean.viewWrapper.nodeList.get(status.index).depth}"/>
</c:if>
</ui:repeat>
You could then access your set variable as #{marginLeftNode} anywhere within that view

JSF Primefaces TabView problems

I asked this in the PF Forum but no one seems to want to answer so I though I'd try my luck here.
I have a ui:repeat that is not being updated correctly after an Ajax call when it is within a TabView.
Simple scenario is I have a ui:repeat pointing at an ArrayList (ArrayList contains simple pojos with a String). Within this I have an h:inputText whose value is the pojo's String getter/setter. The ui:repeat is contained within a h:panelGroup. I use a p:commandButton to run an action to update the ArrayList (just add a couple of objects to it a Math.random value for the String) and then update the h:panelGroup. The updated values in the ArrayList are not reflecting in the ui:repeat input fields. This only appears to be affecting input fields as outputText fields do update correctly. Also if I do the same for a p:dataTable the input field are updated correctly. If I remove the Tabview and Tab tags it works fine.
As it works when removing the Tabs I can only assume this is a bug and not designed to work like this. If someone could please confirm if this is so or if there is a viable work around. I need to use a ui:repeat as my fields are not in a tabular format. This has only occurred since migrating from PF 2.2. I'm currently on PF 3.1, Weblogic 10.3.4 and Mojarra 2.0.4
<p:tabView>
<p:tab title="Test">
<h:form prependId="false">
<p:commandButton id="testStringCheck"
value="Test String Check"
process="#form"
update="testPanel"
action="#{testBean.generateVOwithRandomStrings}">
</p:commandButton>
<h:panelGroup id="testPanel" layout="block">
<ui:repeat value="#{testBean.voList}" var="entry">
<h:outputText value="#{entry.randomString}"/>
<p:inputText style="display:block;"
value="#{entry.randomString}"
size="15">
</p:inputText>
</ui:repeat>
</h:panelGroup>
</h:form>
</p:tab>
</p:tabView>
As a workaround I've used a p:datagrid instead of a ui:repeat. This achieves the look I had in the the ui:repeat so I'm happy. Hopefully this bug will be fixed on future releases.
This is something of a bug in Primefaces commandButton. See the following thread:
http://forum.primefaces.org/viewtopic.php?f=3&t=17454
You can try replacing
<p:commandLink id="testStringCheck" ... update="#form" />
With an <h:commandLink>
<h:commandLink id="testStringCheck" render="#form"/>
Also from the above link here is an interesting method that somebody posted that enables you to correctly find the correct clientId to update.
http://paste.kde.org/177698/
temp solution: insert outside h:panelGroup:
<p:outputPanel defered="true" delay="1" ..>
and update outputPanel instead of panelGroup
Or use a datalist component instead of ui:repeat.
One more, i'm not sure but you can try, so update class instead id:
<h:panelGroup id="testPanel" layout="block" styleClass="testPanelCl" ../>
and update : #(.testPanelCl), don't forget id of panelGroup, without id JSF can not update by class

Use c:set inside ui:repeat does not work

I have a JSF 2 application with the following code:
<c:set var="number" value="0" scope="view" />
<ui:repeat value="${items}" var="item" varStatus="itemIndex">
<c:if test="${item.boolProperty == true}">
<c:set var="number" value="${number + 1}" scope="view" />
</c:if>
<h:outputText value="#{item.name}" />: <h:outputText value="#{number}" />
</ui:repeat>
I want to increase the number depending on the property of the item in the loop. However, the condition seems not to work, since the value of number always stays 0. If I remove the condition, the number is incremented only once, or it is always 0 before incrementing, therefore it outputs 1. Could it be possible the number var changes not to affect the number var that is outside the loop? I believe the scope attribute takes care of that.
JSTL tags and JSF components doesn't run in sync as you'd expect from the coding. JSTL tags runs during building of the JSF view, while JSF components runs during rendering of the JSF view. See for a detailed explanation also JSTL in JSF2 Facelets... makes sense?
What you want to achieve is unfortunately not possible with JSF components. The <ui:param> comes close, but it functions merely as an alias for a more complex EL expression, while the <c:set> actually sets something in the desired scope (the view scope which you've there is by the way wrong).
Your best bet is to change the model or wrap the model in another model so that you end up as
<ui:repeat value="${items}" var="item" varStatus="itemIndex">
<h:outputText value="#{item.name}" />: <h:outputText value="#{item.number}" />
</ui:repeat>

Reuse variable outside of composition - passing variables up in jsf?

I'm using jsf 1.2 and have got some weird javascript which gets repeated at several places in my project.
I do not want to repeat myself.. but i found no way to do something similar to this:
<ui:composition>
<c:set var="confirmBlockJS" value="if (confirm('#{tk:encodeJS(confirmMessage)}')) {#{confirmed}} else{ #{notConfirmed}}"/>
</ui:composition>
Now i want to use the set variable but obv this will fail.
<ui:include src="/blocks/tech/confirmBlock.xhtml">
<ui:param name="confirmMessage" value="#{appTexts['action.logout.title']}"/>
<ui:param name="confirmed" value="return false;"/>
<ui:param name="notConfirmed" value=" #{doJS}"/>
</ui:include>
<h:outputLink id="logout" value="#" rendered="#{renderLogout}"
onclick='#{confirmBlockJS};'
styleClass="_allowEnterKey">
<h:outputText value="#{appTexts['action.logout']}"></h:outputText>
</h:outputLink>
confirmBlockJS is obviously empty at that point, which is actually in my eyes a good thing. But is there no way to pass the variable up? I tried ui:param without luck.
SOLUTION
Use ui:decorate when you want to access variable set with c:set outside of the page which uses the ui:decorate. It will still be visible. In the case of ui:include the c:set will not be visible outside, but ui:param should pass it up (e.g. use ui:param instead of c:set in the ui:include composition)
If you didn't want to inline it as an attribute value, then <ui:decorate> would be the solution for you.
An EL function is closest what you can get to work for this particular functional requirement:
<h:outputLink id="logout" value="#" rendered="#{renderLogout}"
onclick="#{js:confirmBlock(appTexts['action.logout.title'], 'return false;', doJS)}"
styleClass="_allowEnterKey">
<h:outputText value="#{appTexts['action.logout']}"></h:outputText>
</h:outputLink>
or:
<ui:param name="confirmBlock" value="#{js:confirmBlock(appTexts['action.logout.title'], 'return false;', doJS)}" />
<h:outputLink id="logout" value="#" rendered="#{renderLogout}"
onclick="#{confirmBlock}"
styleClass="_allowEnterKey">
<h:outputText value="#{appTexts['action.logout']}"></h:outputText>
</h:outputLink>
Note that generating JS code by Java/JSF/EL this way is a bit a smell. Is it really not possible to make it a simple JS function which you put in a .js file and parameterize it with arguments?

JSF2 and Spring Webflow (<h:commandLink> doesn't respond inside <ui:repeat> facelet tag)

i am trying to have a List of commandLink in every cell of dataTable.
this is small example explaining what i am trying to do
<h:form id="form1">
<p:dataTable id="doctorTable" var="doctor"
value="#{search.medecinsResult}" rowIndexVar="rowIndex">
<p:column headerText="#{search.headerDate[1]}">
<ui:repeat var="seance" value="#{search.column2[rowIndex]}">
<h:commandLink value="#{seance}" action="Reserver"
title="Réservez cette séance">
</h:commandLink>
<br />
</ui:repeat>
</p:column>
</p:datable>
</h:form>
And i define transition on the page viewState in my XML flow:
<view-state id="result">
<transition on="Reserver" to="next">
</transition>
</view-state>
the commandLink work fine outside repeat tag, but when its inside it just reload the webpage
i found JIRA issues for that, but it not resolved.
link to JIRA issue
if there is any workaround it will be great, thank's for your responses.
It's the <ui:repeat> which is the culprit. It doesn't work very well when nested in another repeating component. There are many related issues for that already, the JSF guys are working on that. The usual solution is to pick a "fullworthy" JSF UIData component instead, such as <h:dataTable>. Since you're already using PrimeFaces, I'd suggest to try <p:dataList> instead.

Resources