Dynamic Id's in JSF/Seam - jsf

Got a little problem with a Seam application I'm working on and I was wondering if anyone knows a way round it. I've got a form in my application that uses AJAX to show certain input boxes depending on an item in a dropdown box. The code works fine except for setting the ID's in my input boxes. It looks like JSF doesn't let me set an ID via a variable. Other attributes like "for" in labels are fine. Here's some code explaining what I mean:
<ui:repeat value="#{serviceHome.instance.serviceSettings}" var="currSetting" >
<li>
<!-- Imagine the below works out as "settingABC" -->
<c:set var="labelKey" value="setting#{jsfUtils.removeWhitespace(currSetting.key.name)}" />
<!-- Labelkey is correctly added into this input so for = "settingABC" -->
<h:outputLabel for="#{labelKey}" styleClass="required generated" value="#{currSetting.key.name}:"/>
<s:decorate styleClass="errorwrapper">
<!-- Labelkey ISN'T correctly added into this input. Instead we just get "setting" -->
<h:inputText id="#{labelKey}" value="#{currSetting.value}"/>
<a4j:outputPanel ajaxRendered="true">
<h:message for="#{labelKey}" styleClass="errormessage" />
</a4j:outputPanel>
</s:decorate>
</li>
</ui:repeat>
Does anyone have any idea how I can get past this?

You see why they don't let you set the ID, right? JSF takes over id creation because you're in a repeated loop of components and, if they let you just set the id, you'd end up with duplicate IDs, which wouldn't help you anyway.
Without knowing WHY you want to set the ID explicitly, it's hard to give you a workaround. If it's for JavaScript, you can do what Grant Wagner suggests, and let JSF give you what it put as the id. You can also take a peek at the generated HTML and see what format the id is in. JSF usually uses
"form_id:loop_id:loop_index:component_id"
as the id it generates for components in a form/repeat. You'd have to be sure and give id's to your form and ui:repeat tags to know what they were.
Ok, you answered that you want to have an h:message tag for a specific inputText inside the loop, that's easy.
<h:inputText id="myInput" .... />
<h:message for="myInput" ... />
Now, messages generated for the input will be displayed in the message, and JSF will mangle the "for" attribute (though that isn't generated to HTML) just like it will the "id" attribute in the inputText so they match.
You can even make your OWN messages in your handler code to go to the specific h:message, but you'll need to use a call to clientId to get the target of the message, given the backing bean (not the value backing bean) of the component in question.

I'm assuming you want to control the ID of your input component so you can reference it later in Javascript?
Since you can't set the ID via an expression, I do this:
<h:inputText id="whatever" value="..." />
Then later in the code:
<script type="text/javascript">
var theElement = document.getElementById('<h:outputText value="#{pagecode.whateverClientId}"/ >');
...
</script>
In the pagecode:
protected HtmlInputText getWhatever() {
if (whatever == null) {
whatever = (HtmlInputText) findComponentInRoot("whatever");
}
}
public String getWhateverClientId() {
return getWhatever().getClientId(getFacesContext());
}
Hope that helps.

Have you tried use facelets?
That will allow you to assing your own ids ie:
me:labelKeyThingo can then use the id=#{labelKey} to make a unique label. Here is an example facelet called m:textPassword from my bad code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jstl/core" xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<ui:composition>
<c:set var="styleClass" value="formPrompt" />
<c:set var="requiredLabel" value="" />
<c:choose>
<c:when test="${required=='true'}">
<c:set var="required" value="true" />
<c:set var="styleClass" value="formRequiredPrompt" />
<c:set var="requiredLabel" value="*" />
</c:when>
</c:choose>
<h:panelGroup id="#{id}_formRowTemplateLabel_panelGroup">
<h:outputLabel for="#{id}" styleClass="#{styleClass}" id="#{id}_formRowTemplate_outPut"
value="#{label}" />
<c:if test="${required == 'true'}">
<h:outputText value="#{requiredLabel}" styleClass="formRequiredPromptAsterix"></h:outputText>
</c:if>
</h:panelGroup>
<h:panelGroup id="#{id}_textPasswordTemplate_panelGroup">
<h:inputSecret required="${required}" id="#{id}" value="#{property}"
styleClass="formText">
<f:validator validatorId="Maserati.Password" />
<f:validateLength maximum="16" minimum="8" />
<ui:insert name="additionalTags"></ui:insert>
</h:inputSecret>
<h:message styleClass="formErrorMsg" id="#{id}_textPasswordTemplate_msg" for="#{id}" />
</h:panelGroup>
</ui:composition>
</html>
It is used thusly:
<m:textPassword id="password" label="#{msgs.passwordPrompt}"
property="#{individualApplicationMBean.password}"
required="true" maxlength="16" />

Related

immediate attribute for form validation produces unexpected results in JSF

I checked this post and this post, but neither of those solutions gave me a clear answer for my question I'm having on this post. Please try the example below.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form id="employeeForm">
<h:panelGrid columns="3">
<h:outputLabel for="employeeFirst" value="First: " />
<h:inputText id="employeeFirst" immediate="true" onchange="submit()">
<f:validateLength minimum="3" maximum="30" />
</h:inputText>
<h:message for="employeeFirst" errorStyle="color: red" />
<h:outputLabel for="employeeLast" value="Last: " />
<h:inputText id="employeeLast">
<f:validateLength minimum="3" maximum="30" />
</h:inputText>
<h:message for="employeeLast" errorStyle="color: red" />
<h:outputLabel for="employeeTitle" value="Title" />
<h:inputText id="employeeTitle">
<f:validateLength minimum="3" maximum="30" />
</h:inputText>
<h:message for="employeeTitle" errorStyle="color: red" />
</h:panelGrid>
</h:form>
</h:body>
</html>
If you ran the code above and inserted a value less than 3 characters long into the first input field, you will see a red-colored error message next to the field. This behavior is absolutely fine and expected.
However, if you insert a value between 3 and 30 characters long, the error message for the first field disappears, but the other two input fields produce error messages automatically. I don't want these two error messages to appear automatically after successfully inserting a value into the first input field.
I thought the second and third input fields had immediate attributes set to true in default, so I put immediate attributes and assigned false to each of them, but the result was the same as before.
How can I have only one field in a form to act immediately and not the other fields?
Edit:
I apologize for not making my question clear. I already knew that ajax can handle error message for form validation, but I wanted to let JSF spec leads know that there might be a problem with immediate attribute so that they can fix it for the next release of JSF. I was also hoping that there might be already a solution to this unexpected behavior with immediate attribute, in which case I wanted to hear that through this post. Anyway, thank you for suggesting me I use Ajax for this.
Please use below code. You need to remove onchange="submit().
Instead of submitting everything you can specify exact component which you need to process and update with help of f:ajax. You need to specify list of component ids which you need to process by attribute execute and list of component which you need to update by attribute render.
<h:outputLabel for="employeeFirst" value="First: " />
<h:inputText id="employeeFirst">
<f:validateLength minimum="3" maximum="30" />
<f:ajax execute="#this" render="#this errorMessageBlock" event="blur" />
</h:inputText>
<h:message for="employeeFirst" id="errorMessageBlock" errorStyle="color: red" />

How to construct dynamically attribute name in xhtml - JSF

I want to assign a dynamic value to an input in xhtml page. The ManagedBean contains 3 string attributes: customField1, customField2 and customField3
In the xhtml page I'm looping over a list of values to custruct components:
<ui:repeat value="#{listBean.customFields}" var="item" varStatus="status">
<div >
<p:outputLabel value="#{item.label}" />
<br />
<c:set var="test" value="#{'myBean.customField'.concat(status.index)}"/>
<p:inputText value="#{test}" />
</div>
</ui:repeat>
What I did for concatenation does not work since it concider that the whole expression is a String so it is unable to bind "#{test}" with the bean attribute.
You think it is possible to do that in jsf ?
thanks in advance !
Please try
<p:inputText value="#{myBean['customField'.concat(status.index)]}"/>

Creating a RichFaces popup panel as a Facelets subview/composition not hidable

Popup panels in RichFaces are pretty ugly to work with to be honest. There are several calls to some JavaScripts involved which makes it not easy to derive something that works in general. Anyway, I was trying the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<h:commandLink>
<h:graphicImage library="images/icons" name="#{buttonImageFileName}" />
<rich:tooltip value="#{buttonTooltipText}" direction="bottomRight" />
<rich:componentControl target="#{popupId}" operation="show" />
</h:commandLink>
<rich:popupPanel modal="true"
height="#{popupHeight}"
resizeable="#{popupResizable}"
onmaskclick="#{componentCallToId}.hide(); return false;"
id="#{popupId}">
<f:facet name="header">
<h:outputText value="#{popupHeaderText}" />
</f:facet>
<f:facet name="controls">
<h:outputLink value="#" onclick="#{componentCallToId}.hide(); return false;">
<h:outputText value="X" />
</h:outputLink>
</f:facet>
<p>#{popupSubject}</p>
<p>
<h:inputText value="#{inputTextBean[inputTextProperty]}" styleClass="full-width" id="#{inputTextId}" />
</p>
<h:panelGrid columns="2" style="margin: 0 auto;">
<h:commandButton value="OK"
action="#{acceptButtonBean[acceptButtonMethod](acceptButtonMethodArg)}"
onclick="#{componentCallToId}.hide(); return true;">
<a4j:ajax execute="#this #{inputTextId}" render="#form" />
</h:commandButton>
<h:commandButton value="Cancel" onclick="#{componentCallToId}.hide(); return false;" immediate="true" />
</h:panelGrid>
</rich:popupPanel>
</ui:composition>
This displays an image button which pops up a simple input dialog, which is supposed to be hidden by clicking outside the popup (onmaskclick="..."), by X'ing the popup in the top right corner (<f:facet> with onclick="..."), or by pressing the Cancel <h:commandButton onclick="...">. On OK the AJAX form is supposed to be submitted and the popup is hidden, too. But nothing happens (can't close):
The EL expression #{componentCallToId}.hide(); return false; is the "problem child" in the above. It is not working that way.
In its original, non-Facelets variant here (http://showcase.richfaces.org/richfaces/component-sample.jsf?demo=popup&sample=modalPopup&skin=classic) the call to control the component looks like this:
<h:commandButton value="Cancel" onclick="#{rich:component('add-root-chapter-popup')}.hide(); return false;" immediate="true" />
I pass the following parameters to <ui:include>:
<ui:include src="/subviews/add-node-clink-input-popup.xhtml">
<ui:param name="buttonImageFileName" value="add.png" />
...
<ui:param name="popupId" value="add-root-chapter-popup" />
<ui:param name="componentControlCallToId" value="rich:component('add-root-chapter-popup')" />
...
</ui:include>
Notice the long entry (the rest seems to be working - even the strange syntax for the bean + method + arg, but this is not the focus here).
Q:
Why isn't <ui:param name="componentControlCallToId" value="rich:component('add-root-chapter-popup')" /> working? Currently nothing happens when clicking outside the popup, X'ing, or pressing OK or Cancel (popup staying).
Firebug only shows:
syntax error
.hide(); return false;
Looks like the expression is evaluated to null/empty string.
What's wrong? Can it be fixed? What are my alternatives?
PS: Note, that I've previously tried to use the "popupId" in the Facelets expression like
<h:commandButton value="Cancel" onclick="#{rich:component('popupId')}.hide(); return false;" immediate="true" />
but this has the same result.
Omitting the single quotes did the trick:
<h:commandButton value="Cancel" onclick="#{rich:component(popupId)}.hide(); return false;" immediate="true" />
I thought they were part of JS, but they seem to be EL here.
Also you could try this:-
onmaskclick="#{rich:component('cc.attrs.popupId')}.hide()"
If the quotes cause you any problem use " instead of them.
I believe here you are trying to parse the id to the popup panel dynamically through your custom components exposed variables.
Where in you might be parsing the value for id as
popupId="xyz"
If this being the situation the above solution would work just fine.

Dynamically adding fields to JSF form

I have the following situation that I would like to handle in JSF. My form consists of family information (name/address/phone) and then children information. Since a family can have more then one child, I need to be able to allow the person to click "add more children" and another child "section" will appear.
Here is a simple test case I've thrown together.
Backing Bean. A family has a list of children.
#ViewScoped
#ManagedBean
public class TestBackingBean implements Serializable {
private Family f = new Family();
private Child childToRemove;
public TestBackingBean() {
f.addChild(new Child());
}
public Family getFamily() {
return f;
}
public void setChildToRemove(Child childToRemove) {
this.childToRemove = childToRemove;
}
public TimeZone getTimezone() {
return TimeZone.getDefault();
}
public List<Child> getChildren() {
return f.getChildrenAsList();
}
public Child getChildToRemove() {
return childToRemove;
}
public void addChild() {
f.addChild(new Child());
}
public void removeChild() {
f.removeChild(childToRemove);
}
}
Here is the JSF page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title><ui:insert name="title" />
</title>
<link rel="stylesheet" type="text/css" href="/hcbb/css/main.css" />
</h:head>
<h:body>
<h:form>
<h:panelGroup id="parentSection">
<h:outputLabel value="Parent Name" for="parent_firstName" />
<h:inputText id="parent_firstName" requiredMessage="Required"
immediate="true" label="Parent First Name"
value="#{testBackingBean.family.firstName}">
<f:validateRequired />
</h:inputText>
<rich:message id="parent_firstNameMessage" for="parent_firstName" />
</h:panelGroup>
<h:panelGroup id="childrenSection">
<h:dataTable value="#{testBackingBean.children}" var="child">
<h:column>
<h:panelGrid id="childPanel" columns="3"
style="border:1px solid brown; padding: 5px; margin-bottom:5px; width: 600px;">
<h:outputText id="childTitle" value="Child"
style="font-weight: bold;" />
<h:outputText id="spacer" />
<a4j:commandButton id="removeBtn"
action="#{testBackingBean.removeChild}" immediate="true"
value="Remove Child" render="childrenSection"
style="float:right;" title="Remove">
<f:setPropertyActionListener
target="#{testBackingBean.childToRemove}" value="#{child}" />
</a4j:commandButton>
<h:outputLabel id="child_firstNameLbl" value="First Name" />
<h:inputText id="child_firstName" requiredMessage="Required"
immediate="true" label="Child First Name"
value="#{child.firstName}">
<f:validateRequired />
</h:inputText>
<rich:message id="child_firstNameMessage" for="child_firstName" />
<h:outputLabel id="child_lastNameLbl" value="Last Name" />
<h:inputText id="child_lastName" requiredMessage="Required"
immediate="true" label="Child Last Name"
value="#{child.lastName}">
<f:validateRequired />
</h:inputText>
<rich:message id="child_lastNameMessage" for="child_lastName" />
<h:outputLabel id="child_dobLbl" value="Birth Date" />
<h:inputText id="child_dob" label="Child Birth Date"
immediate="true" requiredMessage="Required"
value="#{child.dateOfBirth}">
<f:convertDateTime id="dobConverter" pattern="MM/dd/yyyy"
timeZone="#{testBackingBean.timezone}" />
<f:validateRequired />
</h:inputText>
<rich:message id="child_dobNameMessage" for="child_dob" />
</h:panelGrid>
</h:column>
</h:dataTable>
<a4j:commandLink id="addChildBtn" immediate="true"
render="childrenSection" action="#{testBackingBean.addChild}"
value="Add Another Child">
</a4j:commandLink>
</h:panelGroup>
</h:form>
</h:body>
</html>
The issue is the saving of the values when adding/removing child sections. If you enter parent name and then child name and date of birth and then click add the fields for the child you just added will disappear? I would have thought that immediate=true on the button and the fields will get them through.
The problem is add a parent first name, enter child info and click the add another child button and the child information you just entered will be erased.
Any suggestions on how I might be able to make this all work. Seems like a fairly simple and somewhat standard use case.
Thanks!
It looks fine at the first glance. The problem symptoms boils down that the f.getChildrenAsList() doesn't return a list with the new child while JSF is about to apply request values. Perhaps that method is re-fetching the list from DB again upon submit? Add a breakpoint to investigate its retun value. Or perhaps the view scope failed and caused the bean to be reconstructed? Add a breakpoint to the bean's constructor. It should not be reconstructed when you're submitting the form against the same view.
As to using the immediate attribute, all your usage of them is entirely superfluous. Just remove them. To understand its use better, get yourself through the Debug JSF lifecycle article (true, it's JSF 1.2 targeted, but the principles are the same for JSF2) and then read particularly this summary:
Okay, when should I use the immediate attribute?
If it isn't entirely clear yet, here's a summary, complete with real world use examples when they may be beneficial:
If set in UIInput(s) only, the process validations phase will be taken place in apply request values phase instead. Use this to prioritize validation for the UIInput component(s) in question. When validation/conversion fails for any of them, the non-immediate components won't be validated/converted.
If set in UICommand only, the apply request values phase until with update model values phases will be skipped for any of the UIInput component(s). Use this to skip the entire processing of the form. E.g. "Cancel" or "Back" button.
If set in both UIInput and UICommand components, the apply request values phase until with update model values phases will be skipped for any of the UIInput component(s) which does not have this attribute set. Use this to skip the processing of the entire form expect for certain fields (with immediate). E.g. "Password forgotten" button in a login form with a required but non-immediate password field.

JSF2.0 with <f:ajax> only works once

I'm having a problem with the tag in JSF2.0 and I hope someone can point out what I'm doing wrong. Here's what I've got in the UI:
<h:panelGroup>
<h:form id="theForm">
<h:selectOneMenu id="theMenu" value="#{viewBean.selectedItem}">
<f:ajax event="change" render="selectedItemText"/>
<f:selectItem itemLabel=""/>
<f:selectItems value="#{viewBean.selectableItems}"/>
</h:selectOneMenu>
<h:outputText id="selectedItemText" value="#{viewBean.selectedItemText}" />
</h:form>
</h:panelGroup>
This is working great - my conversation-scoped backing bean has a method setSelectedItem, and it's called and it does its thing the first time I select a different item from the menu; the output text is updated in the frontend, and I'm happy. However, further changes to the menu selection do not trigger a call to the setter via ajax. I've also tried this with a listener on the f:ajax tag - the listener method is only called that first time as well (breakpoints in the code to figure this out).
Am I doing something incorrectly?
I had a similar problem.
My second commandButton below only works once in the JSF view below that has a view param. Adding <f:param> to my first commandButton solved the problem. This is a situation not covered by BalusC's very helpful discussion.
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:view>
<f:metadata>
<f:viewParam name="id" value="#{fooManager.millis}" required="true"/>
</f:metadata>
<h:head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
</h:head>
<h:body>
<h:form id="fooForm">
<h:commandButton
id="barBbutton"
value="foo:test"
action="#{fooManager.test}">
<f:param name="id" value="1"/>
<f:ajax render="fooMillis1"/>
</h:commandButton>
<p>
<h:outputText id="fooMillis1" value="foo:display1: #{fooManager.millis}"/>
</p>
<p>
<h:outputText id="fooMillis2" value="foo:display2: #{fooManager.millis}"/>
</p>
</h:form>
<h:form id="barForm">
<h:commandButton
id="barButton"
value="bar:test"
action="#{barManager.test}">
<f:ajax render="barMillis1"/>
</h:commandButton>
<p>
<h:outputText id="barMillis1" value="bar:display1: #{barManager.millis}"/>
</p>
<p>
<h:outputText id="barMillis2" value="bar:display2: #{barManager.millis}"/>
</p>
</h:form>
</h:body>
</f:view>
</html>
And my FooManager and BarManager look the same:
#ManagedBean
#ViewScoped
public class FooManager {
public long getMillis() {
return millis;
}
public void setMillis(long millis) {
this.millis = millis;
}
public void test() {
setMillis(System.currentTimeMillis());
}
private long millis;
}
When it is not working, my Weblogic/Mojarra library does not give any helpful hint. There is no error anywhere. It was only after numerous tries that I came up with a working button like the first one above.
I had the same issue.
For the code below ajax was run only once.
<h:inputText id="element_id" value="#{viewBean.someValue}"></h:inputText>
<h:commandLink action="#{viewBean.someAction}" value="click me">
<f:ajax render=":my_form:another_element" execute="element_id> </f:ajax>
</h:commandLink>
When I add to render attribute the element which I'm executing then the ajax is triggered every time.
<h:inputText id="element_id" value="#{viewBean.someValue}"></h:inputText>
<h:commandLink action="#{viewBean.someAction}" value="click me">
<f:ajax render=":my_form:another_element element_id" execute="element_id> </f:ajax>
</h:commandLink>
I had a similar problem, in my case everithing worked fine in all browsers except that in IE9 the ajax was fired only once.
I was using render="#form" and when I changed it to render="#all", it worked fine. I dunno why, since I only have one Form in that page, and all my components are in that form.
So I would advise you to check the render and execute tags, at least in my case it was the solution
I had the same bug, fixed it using Primeface's p:ajax instead of f:ajax.

Resources