JSP to Facelets equivalent for database provided URL linking in loop - jsf-2

I'm porting the servlet/jsp Netbeans' Affableben tutorial to JSF Framework, and want to use Facelets for the view.
I already have the JPA entities, the session beans and the managed beans. I'm starting with the View. However, I have not found the equivalent in Facelets to work around this line:
<a href="<c:url value='category?${category.id}'/>">
This is the full loop, both in jsp and facelets:
JSP code:
<c:forEach var="category" items="${categories}">
<div class="categoryBox">
<a href="<c:url value='category?${category.id}'/>">
<span class="categoryLabel"></span>
<span class="categoryLabelText"><fmt:message key='${category.name}'/></span>
<img src="${initParam.categoryImagePath}${category.name}.jpg"
alt="<fmt:message key='${category.name}'/>" class="categoryImage">
</a>
</div>
</c:forEach>
Equivalent Facelets code:
<ui:repeat var="category" value="${categoryController.items}">
<div class="categoryBox">
<h:link outcome="${category.id}"/>
<span class="categoryLabel"></span>
<span class="categoryLabelText">${category.name}</span>
<img src="./resources/img/categories/${category.name}.jpg"
alt="${category.name}" class="categoryImage"/>
</div>
</ui:repeat>
This line is not working in Facelets as expected:
<h:link outcome="${category.id}"/>
What would be a working equivalent in Facelets?
EDIT 1
public String getName() throws UnsupportedEncodingException {
return URLEncoder.encode(name, "UTF-8");
}
Warning message: Unable to find resource img/categories/fruit+%26+veg.jpg

The <h:link> utilizes JSF implicit navigation and requires a real (implicit) navigation outcome value. You need to specify the view ID in the outcome. You need to specify request parameters by <f:param>. You also need to nest the spans and the image in the link as you did in your initial example. Assuming that you have a category.xhtml file in the root, this should do:
<h:link outcome="category">
<f:param name="id" value="#{category.id}" />
<span class="categoryLabel"></span>
<span class="categoryLabelText">#{category.name}</span>
<img src="./resources/img/categories/#{category.name}.jpg"
alt="#{category.name}" class="categoryImage"/>
</h:link>
Unrelated to the concrete question, you should be using <h:graphicImage> instead of <img> as well. This way JSF will ensure that the src is properly set. In your particular case that would be
<h:graphicImage name="img/categories/#{category.name}.jpg"
alt="#{category.name}" class="categoryImage"/>
(note that I replaced ${} by #{}, just to adhere the standard and for the consistency)

You can change from this line:
<a href="<c:url value='category?${category.id}'/>">
to this:
<h:link outcome="category.xhtml?id=#{category.id}" />
<h:link outcome="category">
<f:param name="id" value="#{category.id}" />
</h:link>
<h:outputLink value="category.xhtml?id=#{category.id}" ></h:outputLink>

Related

ui:include parameter passing does not work when remote page is included

I have a basic UI (index.html) that is divided into Header, Footer and Content. The content-page is either on the same (local.xhtml) server like the index.html or on another (remote.xhtml) server.
Including the pages and dynamically reloading them with ajax works pretty good. But parameter passing only works on the local content page. The parameter is retrieved of a Bean called Login which also is on the same server as the index.html.
index.xhtml (excerpt):
<h:panelGroup id="content" layout="block">
<ui:include src="#{contentLoader.page}" >
<ui:param name="userName" value="#{login.userName}" />
</ui:include>
</h:panelGroup>
<h:form>
<f:ajax render=":content">
<ul>
<li><h:commandLink value="include1"
action="#{contentLoader.LocalPage}" /></li>
<li><h:commandLink value="include2"
action="#{contentLoader.remotePage}" /></li>
</ul>
</f:ajax>
</h:form>
local.xhtml
<h:body>
<ui:composition>
<h:form id="form">
<h:outputText value= "Local Page. Parameter is: #{userName}"/>
</h:form>
</ui:composition>
</h:body>
remote.xhtml
<h:body>
<ui:composition>
<h:form id="form">
<h:outputText value= "Remote Page. Parameter is: #{userName}"/>
</h:form>
</ui:composition>
</h:body>
local.xhtml prints out: "Local Page. Parameter is: MyUser"
remote.xhtml only: "Remote Page. Parameter is: "
I am using Glassfish4 as WebServer and JSF2
Thank you. The hints in the comments solved my Problem. For now this works fine for me:
<iframe> was solving my problem. Parameter passing within URL and JSF works brilliant.
Just "including" the remote page with <iframe src="#{myBean.Url}"></iframe> and reading the parameter with JSF Function "#{param['param1']}"
{myBean.Url} return a String in this format: localhost:8680/MyServiceservice/faces/myPage.html?param1=value1 with value1 being the parameter I want to transfer.

How to use generated ids in EL (jsf, composite)?

I want to have a composite that composes
<h:form id="f_imgA" >
<h:graphicImage id="imgA"
onclick="document.getElementById('#{k_imgA.clientId}').value=mods(event)"
value="images/img?r=#{Math.random()}">
<f:ajax event="click" listener="#{mBean.handleEvent}"
execute="#this k_imgA" render="#this"></f:ajax>
</h:graphicImage>
<h:inputHidden id="k_imgA" binding="#{k_imgA}" value="#{mBean.keyX}" />
</h:form>
when I write
<comps:cimg imgId="imgA" />
The original purpose of this code is to send the modifier-states (Ctrl, Shift, Alt) to the server.
I have
<composite:interface>
<composite:attribute name="imgId" />
</composite:interface>
<composite:implementation>
<h:form id="f_#{cc.attrs.imgId}">
<h:graphicImage id="#{cc.attrs.imgId}"
onclick="document.getElementById('#{k_${cc.attrs.imgId}.clientId}').value=mods(event)"
value="images/img?r=#{Math.random()}">
<f:ajax event="click" execute="#this k_#{cc.attrs.imgId}"
listener="#{mBean.handleEvent}" render="#this">
</f:ajax>
</h:graphicImage>
<h:inputHidden id="k_#{cc.attrs.imgId}"
binding="k_#{cc.attrs.imgId}" value="#{mBean.keyX}" />
</h:form>
</composite:implementation>
which, quite expected, does not work. The offending expression is
#{k_${cc.attrs.imgId}.clientId}
which is intended to return the clientId of the hiddenInput with id k_imgA . As far as I know, EL cannot handle nested expressions like the one above, but it was worth a try. So is there a simple, straightforward way to get the clientId of k_imgA? I don't want to use more javascript, if this can be avoided.
Edit:
don't get confused about #{Math.random()}, it works just because I have a bean called "Math".
The javascript function mods is given by
<h:outputScript target="body">function mods(event) {return ((event.ctrlKey)?1:0)+((event.shiftKey)?2:0)+((event.altKey)?4:0)} </h:outputScript>
You don't need to fiddle with all those _#{cc.attrs.imgId}. Just give the composite a fixed id. They are already naming containers themselves. JSF will then worry about the rest.
<composite:implementation>
<h:form id="f">
<h:graphicImage id="i" ... />
<h:inputHidden id="k" ... />
</h:form>
</composite:implementation>
Usage:
<comps:cimg id="imgA" />
Generated HTML:
<form id="imgA:f" ...>
<img id="imgA:f:i" ... />
<input id="imgA:f:k" ... />
</form>
As to the JS attempt, you'd best use element's own ID as base:
<h:graphicImage onclick="document.getElementById(id.substring(0,id.lastIndexOf(':')+1)+'k').value='...'" />
Or, easier, if the hidden element is guaranteed to be the direct sibling of the image element in the generated HTML DOM tree, then just grab it by Node#nextSibling:
<h:graphicImage onclick="nextSibling.value='...'" />
<h:inputHidden ... />
The binding will never work as in your attempted construct, and even then you'd best do it via a Map in request scope or a so-called backing component.
See also:
Accessing JSF nested composite component elements in JavaScript
Integrate JavaScript in JSF composite component, the clean way
Rerendering composite component by ajax

Richfaces tooltip not working with h:selectOneRadio

I would like to "bind" a tooltip to a h:selectOneRadio.
Following the example found here, I tried with
<td>
<h:selectOneRadio id="subscriptionType" value="#bean.subscriptionType}">
<f:selectItems value="#{beanModel.subscriptionTypeValues}" />
<rich:tooltip id="tt1" for="subscriptionType" layout="block" >
<span style="white-space: nowrap">
Data is for laptop, modem, ...<br />
Voice is for smartphone, ...
</span>
</rich:tooltip>
</h:selectOneRadio>
<h:messages for="subscriptionType" style="color:red; font-size:12px;" />
</td>
but the tooltip doesn't appear...
Do I miss something or it is not possible to use tooltips with radio buttons?
Problem solved.
I didn't see an error message at the bottom of the page saying
One or more resources have the target of 'body', but no 'body'
component has been defined within the view
So, after having googled for the error message I came to the solution posted here:
use h:body tag, instead of body
and now it works!

Display JSF element only if specific h:message is being displayed

I have a h:form with several inputs and each of them got its own h:message and I'm looking for a way to show (using render or assigning some styleClass) some other element only when specific h:message is being shown (and hide when that h:message is not being displayed).
Here a code snippet
<li>
<h:panelGroup id="current_password_wrapper">
<p:password value="#{myBean.myCurrPass}" id="current_password" required="true"
styleClass="required_field" />
</h:panelGroup>
<h:message for="current_password"/>
</li>
<li>
<h:panelGroup id="new_password_wrapper">
<p:password value="#{myBean.myNewPass}" id="new_password" required="true"/>
</h:panelGroup>
<h:message for="new_password"/>
<h:commandLink value="my value"/>
</li>
I want to make the h:commandLink visible only when the <h:message for="new_password"/> is being displayed
So far I couldn't find anything...
If your environment supports EL 2.2, then you could check if FacesContext#getMessageList() isn't empty for the particular client ID.
<p:password binding="#{new_password}" ... />
<h:commandLink ... rendered="#{not empty facesContext.getMessageList(new_password.clientId)}" />
If the message is being shown as result of a validation error, then you could also just check the UIInput#isValid() state of the component associated with the message.
<p:password binding="#{new_password}" ... />
<h:commandLink ... rendered="#{not new_password.valid}" />
Note that manually adding a faces message to the context won't mark the input component invalid. Therefor either a true Validator should be used which throws a ValidatorException, or an explicit input.setValid(false) call has to be done programmatically.
I think with the answer to this question you requirement can be archived:
How to number JSF error messages and attach number to invalid component
I think you can do something like this:
<h:outputText value="output text" rendered="#{bean.messageIndexes['form:input1'] > 0}" />

<c:if><c:otherwise> does not work, both conditions evaluate like true

I am trying to toggle between two different command buttons depending on whether a list contains the given item ID:
<c:if test="#{roomServiceManagerBean.holdinghotelvilla.contains(hotel.hotelvillaId)}">
<p:commandButton ajax="true" id="commanddeactivate" update=":roomserviceForm:hoteltable,:roomserviceForm:msgs" actionListener="#{roomServiceManagerBean.deactivateServiceForHotel(hotel.hotelvillaId)}" icon="ui-icon-radio-off" type="submit" value="Remove Service">
<f:param name="roomserviceid" value="#{roomServiceManagerBean.roomServiceId}" />
</p:commandButton>
</c:if>
<c:otherwise>
<p:commandButton id="commandactivate" update=":roomserviceForm:hoteltable,:roomserviceForm:msgs" actionListener="#{roomServiceManagerBean.activateServiceForHotel(hotel.hotelvillaId)}" icon="ui-icon-radio-on" type="submit" value="Provide Service">
<f:param name="roomserviceid" value="#{roomServiceManagerBean.roomServiceId}" />
</p:commandButton>
</c:otherwise>
However, it fails and the both buttons appear. How is this caused and how can I solve it?
The <c:if> will in this construct fail if #{hotel} is not available during view build time but only during view render time (e.g. because it's definied as <p:dataTable var>). The <c:otherwise> is completely displaced here. It belongs to a <c:choose><c:when>. Technically, you should be using <c:if> instead with a negation in the test. Or, you should be replacing the first <c:if> by a <c:when> and wrap the whole thing in <c:choose>. However that would still fail if #{hotel} is not available during view build time.
Just use JSF component's rendered attribute instead.
<p:commandButton ... rendered="#{roomServiceManagerBean.holdinghotelvilla.contains(hotel.hotelvillaId)}">
...
</p:commandButton>
<p:commandButton ... rendered="#{not roomServiceManagerBean.holdinghotelvilla.contains(hotel.hotelvillaId)}">
...
</p:commandButton>
See also:
EL expression in c:choose, can't get it working
JSTL in JSF2 Facelets... makes sense?

Resources