How to construct dynamically attribute name in xhtml - JSF - 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)]}"/>

Related

"#{serviceCatalogueController.allMap[category.key]}": Property 'key' not found on type java.util.HashMap$KeySet

I am trying to populate a map with values from inputText and inputTextArea. Also Date. In the backbean I have a map of like Map>
Basically, a Category can have many Attributes. These Attributes are input fields. For multiselect, dropdown and single select all i need is to set the attribute. But for TextArea, textField and Date I need to set the attribute plus the value which is why I have the String.
my jsf looks like
<p:dataList id="serviceCatalogueCriteria" var="category" value="#{serviceCatalogueController.allMap.keySet()}">
<div id="categoryDiv" style="overflow: hidden;">
<div class="category-header">
<h:outputText value="#{serviceCatalogueController.allMap[category.key]}" />
</div>
<div>
<!-- Text field, text area or date -->
<div class="category-text">
<ui:fragment
rendered="#{categoryService.isTextField(category) or categoryService.isTextArea(category) or categoryService.isDate(category)}">
<ui:fragment
rendered="#{categoryService.isTextField(category)}">
<p:dataList var="attribute" value="#{category.entrySet()}" >
<p:inputText
value="#{category[attribute.key]}" />
</p:dataList>
</ui:fragment>
<ui:fragment
rendered="#{categoryService.isTextArea(category)}">
<p:dataList var="attribute" value="#{category.entrySet()}" >
<p:inputTextarea rows="3" cols="70"
value="#{category[attribute.key]}"/>
</p:dataList>
</ui:fragment>
<ui:fragment rendered="#{categoryService.isDate(category)}">
<p:dataList var="attribute" value="#{category.entrySet()}" >
<p:calendar
value="#{category[attribute.key]}"
showOn="button">
</p:calendar>
</p:dataList>
</ui:fragment>
</ui:fragment>
</div>
<p:separator />
</p:dataList>
And my back bean looks like
private Map<Category,Map<Attribute,String>> allMap;
//setter and getter
The error I get is
javax.el.PropertyNotFoundException: /resources/PWAssessment/ServiceCatalogueFilters.xhtml #24,84 value="#{serviceCatalogueController.allMap[category.key]}": Property 'key' not found on type java.util.HashMap$KeySet
Why would this not work?
There are 2 mistakes.
<p:dataList> can't iterate over a Set<E> (nor Map<K, V>). It can only iterate over List<E> or E[] or DataModel<E>.
Even if it would have worked, the var="category" represents the Category instance itself, not some Map. If the <p:dataList> would have supported Set<E>, you should just have used
<h:outputText value="#{serviceCatalogueController.allMap[category]}" />
And, equivalently, further in the code, the #{category.entrySet()} wouldn't have worked either, as the #{category} would represent the Category instance itself.
The <p:dataList> supports iterating over an array. So, this should do:
<p:dataList value="#{serviceCatalogueController.allMap.entrySet().toArray()}" var="categoryEntry">
This is Category: #{categoryEntry.key}
This is Map<Attribute,String>: #{categoryEntry.value}
...
<p:dataList value="#{categoryEntry.value.entrySet().toArray()}" var="attributeEntry">
This is Attribute: #{attributeEntry.key}
This is String: #{attributeEntry.value}
This is quite inefficient though. I strongly recommend to remodel the model as such that you just have something like a List<CategoryDTO>. Otherwise, grab <c:forEach> which supports efficiently iterating over a Map:
<c:forEach items="#{serviceCatalogueController.allMap}" var="categoryEntry">
This is Category: #{categoryEntry.key}
This is Map<Attribute,String>: #{categoryEntry.value}
...
<c:forEach items="#{categoryEntry.value}" var="attributeEntry">
This is Attribute: #{attributeEntry.key}
This is String: #{attributeEntry.value}

Dynamic navigation with parameter passing in JSF

I want to pass the "title" parameter in the following listing dynamicaly to another jsf Facelet, depending on the selection of the selectOneMenu. My first approach looks like this:
<h:form id="form">
<p:selectOneMenu value="#{exerciseEditorBean.selectedExerciseType}" >
<f:selectItem itemLabel="Multiple Choice Exercise" itemValue="MultipleChoiceExercise" />
<f:selectItem itemLabel="Vocabulary Test" itemValue="VocabularyTest" />
</p:selectOneMenu>
<h:outputText value="Enter Title of your Exercise: " />
<h:inputText id="title" value="#{exerciseEditorBean.exerciseTitle}" />
<h:commandButton value="Next" action="#{exerciseEditorBean.openEditor()}" />
</h:form>
The ExerciseEditorBean is ViewScoped.
The openEditor() function then decides by the selectedExerciseType attribute which Facelet to show next and returns something like "multipleChoiceEditor.xhtml".
How can I now pass the titel attribute to this Facelet?
I now use the f:ViewParam in the target servelet, which works well except, that "multipleChoiceEditor.xhtml?includeViewParams=true" does not work, but this is another issue. Thanks for the discussion!

JSF richfaces getElementById

I am using jsf2 and richfaces 4.X how can i get the richfaces enabled input field's current value ? equal to getElementById('field_name').vlue
I tried some of the methods named like findcomponent.value and element.value but they give me old value which was while page was loaded b/c findcomponent and element method returns server side UI.components instead client side components ?
I guess you are to use rich:clientId function to render a correct identifier into your java script.
For example:
var myElement = document.getElementById("#{rich:clientId('field_name')}");
See also RichFaces rich:clientId within facelets
If you check the HTML generated, you could see that every JSF / RF element has his id like :. For example:
<h:form id="frmSample">
<h:inputText id="txtSample" value="#{mybean.someTextValue}" />
</h:form>
The HTML generated will be:
<form method="POST">
<input type="text" id="frmSample:txtSample" />
</form>
So, in JavaScript you could reference the element by this id.
var txtValue = document.getElementById('frmSample:txtSample').value;
Also, for the RF composite HTML components like rich:tab or rich:calendar you could use the component ID generated by HTML but I'll recommend "#{rich:clientId('field_name')}" as #DRCB has explained in his post.
To get the richfaces components values use the rich:component and the getValue() methods.
To get the jsf library components values use the rich:element and the value JS methods.
Example:
<h:form>
<h:inputText id="textField" value="#{bean.value1}" />
<a4j:commandButton value="displayTextField" action="doSomething()"
onclick="alert('v:'+ #{rich:element('textField')}.value); return true;" />
<rich:inplaceInput id="richField" value="#{bean.value1}" />
<a4j:commandButton value="displayRichField" action="doSomething()"
onclick="alert('v:'+ #{rich:component('richField')}.getValue()); return true;" />
</h:form>
They both work even in a rich:dataTable, without adding the id of the datatable or something. Richfaces is quite smart and find the ids of the 'current row'
example:
<h:form>
<rich:dataTable id="mydatatable" value="bean.findValues()" var="myvar">
<rich:column>
<h:inputText id="textField" value="#{myvar.text1}" />
<a4j:commandButton value="displayTextField" action="doSomething()"
onclick="alert('v:'+ #{rich:element('textField')}.value); return true;" />
</rich:column>
<rich:column>
<rich:inplaceInput id="richField" value="#{myvar.text2}" />
<a4j:commandButton value="displayRichField" action="doSomething()"
onclick="alert('v:'+ #{rich:component('richField')}.getValue()); return true;" />
</rich:column>
</rich:dataTable>
</h:form>

Change the properties of an Input within a ui:repeat

I'd like to change the "required" property of an InputText that is located within an ui:repeat, but I'm not able to access to the component from the ManagedBean:
<h:selectManyCheckbox id="required" value="#{test.required}"
layout="lineDirection" converter="javax.faces.Integer">
<f:ajax event="change" listener="#{test.update}" />
<f:selectItems value="#{test.selectable}"></f:selectItems>
</h:selectManyCheckbox>
<ui:repeat value="#{test.names}" var="name" id="repeat">
<h:panelGrid columns="3">
<h:outputLabel id="nameLabel">name:</h:outputLabel>
<h:inputText id="name" value="#{name}"
validator="#{test.validateName}" />
<h:message for="name"></h:message>
</h:panelGrid>
</ui:repeat>
I'm trying to use the findComponent method, but it does not work:
public void update(AjaxBehaviorEvent event) {
for(Integer i: selectable) {
UIViewRoot vr = FacesContext.getCurrentInstance().getViewRoot();
HtmlInputText input = (HtmlInputText)vr.findComponent("form:repeat:"+i+":name");
input.setRequired(required.contains(i));
}
}
The ui:repeat doesn't repeat the components in the view root, it repeats the component's output in the rendered HTML output.
There are several ways to achieve this properly. One of them is to use a value object instead and set the requireness there. E.g. a List<Item> wherein Item has the properties String name and boolean required.
<ui:repeat value="#{test.items}" var="item" id="repeat">
<h:panelGrid columns="3">
<h:outputLabel id="nameLabel">name:</h:outputLabel>
<h:inputText id="name" value="#{item.name}" required="#{item.required}" validator="#{test.validateName}" />
<h:message for="name"></h:message>
</h:panelGrid>
</ui:repeat>
There are more ways, but since the JSF version you're using and the functional requirement is unclear, it's only guessing which way is the most applicable in your case.

Dynamic Id's in JSF/Seam

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" />

Resources