`h:commandLink` action is not invoked ( maybe because of `ui:repeat`) - jsf

Here is code:
<ui:repeat var="entity" varStatus="status" value="#{myentityListView.someList}">
<h:form>
<h:commandLink value="Go!" action="mypage.xhtml" >
<c:if test="#{entity.entityType=='Comment'}"><f:param name="productId" value="#{entity.product.getId()}"/></c:if>
<f:param name="userId" value="#{entity.user.getId()}"/>
</h:commandLink>
</h:form>
</ui:repeat>
Maybe its cause is that h:commandLink is in ui:repeat.
mypage.xhtml is an exixting page.
Thanks

You need to make sure that #{myentityListView.someList} returns exactly the same value during the form submit request as it was during the request of displaying the page. Putting the bean in the view scope (just mark it #ViewScoped) and ensuring that you preserve the list during (post)constructor or in an action method should fix it.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
However, in your particular case, it's much better to just use <h:link> instead as you don't seem to need to send a POST request at all. This way you end up with nice bookmarkable and searchbot-chipherable links.
<ui:repeat var="entity" varStatus="status" value="#{myentityListView.someList}">
<h:form>
<h:link value="Go!" outcome="mypage.xhtml">
<f:param name="userId" value="#{entity.user.id}" />
<f:param name="productId" value="#{entity.product.id}" disable="#{entity.entityType != 'Comment'}" />
</h:link>
</h:form>
</ui:repeat>
Also note that I fixed your <c:if> approach by removing it as it won't work as you'd expect. It would always evaluate false. See also JSTL in JSF2 Facelets... makes sense?
See also:
When should I use h:outputLink instead of h:commandLink?

Related

Conditional rendering of f:param in JSF

I'm using an <h:outputLink> as follows.
<c:set var="cid" value="1"/>
<c:set var="sid" value="2"/>
<h:outputLink value="Test.jsf">
<h:outputText value="Link"/>
<f:param name="cid" value="#{cid}"/>
<f:param name="sid" value="#{sid}"/>
</h:outputLink>
This is just an example. Both of the query-string parameters are dynamic. So, <c:set> used here is just for the sake of demonstration.
At any time, either one, both or none of the parameters may be present. In case, if only one or none of them is present then, parameter/s are unnecessarily appended to the URL which should not happen. Preventing unnecessary query-string parameters from being appended to the URL requires a conditional rendering of <f:param>.
JSTL <c:if> like the following
<c:if test="${not empty cid}">
<f:param name="cid" value="#{cid}"/>
</c:if>
did not work.
How can it be made possible to conditionally render <f:param> inside <h:outputLink>?
The <f:param> has a disable (not disabled!) attribute for the purpose.
<f:param name="cid" value="#{cid}" disable="#{empty cid}" />
<f:param name="sid" value="#{sid}" disable="#{empty sid}" />
Note that this has a bug in Mojarra versions older than 2.1.15, because they typo'ed the actual UIParameter property to be disble instead of disable. See also issue 2312.
As to the <c:if> approach, that would only work if the #{cid} and #{sid} is available during view build time. In other words, it would fail if they are only available during view render time, e.g. when they depend on var of a repeater component. See also JSTL in JSF2 Facelets... makes sense?
See also:
f:param tag attribute 'disable' is not work
Don't you like this kind of a solution?
<f:param name="#{cid == null ? '' : 'cid'}" value="#{cid}"/>
<f:param name="#{sid == null ? '' : 'sid'}" value="#{sid}"/>

div id not getting fetched if under c:forEach

I am trying to allocate id from backing bean to div element using below code:
<c:forEach var="item" items="#{backingBean.dataModel}">
<t:div id="xyz_#{item.id}" forceId="true" forceIdIndex="false" title="#{item.name}" style="display:none">
<ui:include src="#{item.view}">
<ui:param name="id" value="#{item.id}" />
<ui:param name="model" value="#{item.model}" />
</ui:include>
</t:div>
</c:forEach>
When page is getting loaded for the first time, it assigns correct id as inferred from backing bean. When I refresh the section of page with this code, it do not call getId method of backing bean but calls getView, getModel correctly. As a result, div has incorrect Id.
It might the case that div id is allocated prior to c:forEach execution. How do I enforce div to use Id from backing bean when it is inside c:forEach?
The id (and binding) attributes of JSF UI components are evaluated during view build time (when the JSF component tree is built for the first time), not during view render time nor during future reuse of the very same JSF component tree in subsequent postbacks to the same view.
I'm not exactly sure why you're approaching it with a <t:div> like that. It would make more sense to use a plain HTML <div> in this particular case.
<c:forEach var="item" items="#{backingBean.dataModel}">
<div id="xyz_#{item.id}" title="#{item.name}" style="display:none">
<ui:include src="#{item.view}">
<ui:param name="id" value="#{item.id}" />
<ui:param name="model" value="#{item.model}" />
</ui:include>
</div>
</c:forEach>
See also:
JSTL in JSF2 Facelets... makes sense?

<c:foreach> tag not evaluating an object

I have the following piece of code:
<h:outputText value="#{lecture.lectureName}" />
<c:forEach items="#{criterionController.getCriteriaForLecture(lecture)}" var="criterion">
<h:outputText value="#{criterion.criterionName}" />
<h:commandLink value="Edit"/>
<h:commandLink value="Delete"/>
</c:forEach>
The output text part is working perfectly and displays what it should display so this proves that the lecture object is set. However the for each tag gives a null pointer exception. When I debugged the code, I saw that the lecture object was taken as null when the method getCriteriaForLecture() was called.
How can this behaviour explained?
This can happen if the lecturer variable is in turn been set by a JSF iterating component such as <h:dataTable>, <ui:repeat>, etc or probably a <p:tabView>, based on your previous question.
A more detailed explanation of this behaviour can be found here: JSTL in JSF2 Facelets... makes sense? To the point, JSTL tags runs during building the view, not during rendering the view. The lecturer variable is in your particular case only available during rendering the view and is thus always null during building the view, when JSTL runs.
To solve it, use a normal JSF component like <ui:repeat> instead.
<ui:repeat value="#{criterionController.getCriteriaForLecture(lecture)}" var="criterion">
<h:outputText value="#{criterion.criterionName}" />
<h:commandLink value="Edit"/>
<h:commandLink value="Delete"/>
</ui:repeat>
Much better would be not doing business actions in getters at all. Just make the List<Criterion> a property of Lecture instead.
<ui:repeat value="#{lecture.criterions}" var="criterion">
<h:outputText value="#{criterion.criterionName}" />
<h:commandLink value="Edit"/>
<h:commandLink value="Delete"/>
</ui:repeat>
See also Why JSF calls getters multiple times

Setting <f:param> value with <ui:repeat> var

<h:form>
<ui:repeat value="#{sampleManagedBean.food}" var="food">
<h:commandLink value="Name" action="#{sampleManagedBean.outcome}">
<f:param name="name" value="ssd" />
<f:param name="v" value="#{food.boy}" />
</h:commandLink>
<h2>#{food.boy}</h2>
</ui:repeat>
</h:form>
I can't get the the second <f:param> value which is set based on <ui:repeat var>. I can get only the first one which is hardcoded.
The ui:repeat is an UI component while f:param is a taghandler (like JSTL). Taghandlers run during view build time before UI components which run during view render time
(see here).
In our case it means that in the view build phase f:param knows nothing about #{food.boy}. c:forEach will be fine, but if we call some kind of ajax action to change the size of#{sampleManagedBean.food} and rerender the form, we'll not see any changes on page. Because partial rerendering (ajax) affects only UI component tree. c:forEach is somewhere between hardcoding and ui:repeat, we'll have to reload the page to see changes.
try this way,
<h:form>
<ui:repeat value="#{sampleManagedBean.food}" var="food">
<h:commandLink value="Name" action="#{sampleManagedBean.outcome}">
<f:setPropertyActionListener value="ssd" target="#{sampleManagedBean.name}" />
<f:setPropertyActionListener value="#{food.boy}" target="#{sampleManagedBean.v}" />
</h:commandLink>
</ui:repeat>
</h:form>

Why doesn't h:commandButton execute the action method when combined with c:chose?

I've seen a strange problem in my project. It's that <h:commandButton/> does not execute the action method.
<c:choose>
<c:when test="#{empty param.t}">
// HTML
</c:when>
<c:when test="#{param.t eq 'normal'}">
// HTML
<h:form>
<h:commandButton value="ADD" action="#{addBean.doSomething}" />
</h:form>
<c:when>
</c:choose>
When I move <h:form> into first c:when, then the action method is called. Otherwise, it isn't. Why?
I'll ignore the syntax error in your EL (a missing }).
The command button won't be executed when #{param.t eq 'normal'} evaluates to false at the point the form submit request is to be processed. You need to maintain the same parameter for the subsequent request so that the button will be rendered so that JSF can confirm that the enduser is allowed to invoke the action. You can do this by adding a <f:param>:
<h:form>
<h:commandButton value="ADD" action="#{addBean.doSomething}">
<f:param name="t" value="#{param.t}" />
</h:commandButton>
</h:form>
Note that this is supported since JSF 2.0 only. On JSF 1.x you'd need to replace h:commandButton by a h:commandLink if you want f:param support.
Unrelated to the concrete problem, you should try to avoid JSTL as much as possible in your JSF views. If the intent is to render view parts conditionally (not to build view parts conditionally), then you should rather be using the JSF component's rendered attribute instead of a JSTL <c:choose> or <c:if>:
<h:panelGroup rendered="#{empty param.t}">
// HTML
</h:panelGroup>
<h:panelGroup rendered="#{param.t eq 'normal'}">
// HTML
<h:form>
<h:commandButton value="ADD" action="#{addBean.doSomething}" />
</h:form>
</h:panelGroup>

Resources