Assign unique ids to <div> inside <c:forEach> - jsf

I want to assign a unique id for the <div> enclosed in the <c:forEach>. Whenever the page is rendered all the <div>s generated by the <c:forEach> have the same id. Is there any way to assign unique id for all the divs generated by the <c:forEach>? I have tried using <ui:repeat> but I was having issues with it so I decided to stick with <c:forEach>.
Facelet:
<c:forEach var="p" items="#{statusBean.statusList}">
<h:form>
<div class="status">
// Content
</div>
</h:form>
</c:forEach>

Use the c:forEach attribute varStatus to define a variable that will contain the status of the loop. Then you can use it in your template like this:
<c:forEach var="p" items="#{statusBean.statusList}" varStatus="loop">
<h:form>
<div class="status_#{loop.count}">
// Content
</div>
</h:form>
</c:forEach>
You can also use #{loop.index} if you want it initiated with 0.

Try using a <h:panelGroup> or another JSF component to render your divs.
http://docs.oracle.com/javaee/5/javaserverfaces/1.2/docs/tlddocs/
This will cause unique IDs to get generated for you.

Related

Omnifaces TagAttribute Id cannot be used as id

I have the following Facelet Taglib:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:o="http://omnifaces.org/ui"
xmlns:h="http://java.sun.com/jsf/html">
<o:tagAttribute name="id"/>
<h:panelGroup id="#{id}" layout="block" styleClass="idTest">
#{id}
</h:panelGroup>
</ui:composition>
The taglib.xml looks like this:
<tag>
<tag-name>idTest</tag-name>
<source>resources/myProject/tags/idTest.xhtml</source>
</tag>
And the code, where it is used is simply:
<myProject:idTest/>
How can it be, that the following HTML is being rendered:
<div class="idTest">
j_ido489794984_4bf870cd
</div>
Why does my PanelGroup have no id? The id is generated like it is expected based on the documentation of o:tagAttribute, since the content of the div is rendered. But as id it does not work. Why?
This is indeed confusing.
The documentation literally says:
... it will autogenerate an unique ID in the form of j_ido[tagId] where [tagId] is the <o:tagAttribute> tag's own unique ID.
But the actual behavior is more like so:
... it will override any autogenerated ID into the form of j_ido[tagId] where [tagId] is the <o:tagAttribute> tag's own unique ID.
In other words, when JSF itself needs to render the id attribute of a HTML element, usually because it's required by some internal logic further down in the chain, such as <f:ajax> and friends, and there is no explicit ID specified on the tag like so <x:someTag id="fixedId" />, then JSF will by default autogenerate one in the form of j_id[autoIncrementInteger]. But this will go wrong on tagfiles because the autoIncrementInteger may get bumped further by one on each postback depending on the JSF impl and view state configuration used. The <o:tagAttribute> simply attempts to ensure this way that the autogenerated ID stays the same on each postback.
When you edit your test tagfile to add <f:ajax>,
<h:panelGroup id="#{id}" layout="block" styleClass="idTest">
<f:ajax event="click" />
</h:panelGroup>
then you'll see that the generated <div> has an id, because this is technically required by <f:ajax>.
<div id="j_ido-1512689859_13a7e7e3" class="idTest"
onclick="mojarra.ab(this,event,'click',0,0)">
</div>
Or when you swap <h:panelGroup> for e.g. a <h:form> or whatever component which always requires an ID in the client side,
<h:form id="#{id}" styleClass="idTest">
<ui:insert />
</h:form>
then you'll also see that it's generated.
<form id="j_ido-1512689859_13a7e7e3" name="j_ido-1512689859_13a7e7e3" method="post" action="/test.xhtml" class="idTest" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="j_ido-1512689859_13a7e7e3" value="j_ido-1512689859_13a7e7e3" />
...
</form>
In other words, the feature is working fine, but it was simply not used in your specific case because JSF didn't consider it necessary to generate it.
I've in the meanwhile updated the documentation.

accessing var outside ui:repeat JSF2

I want to access a variable through out my page. The var is declared inside a ui:repeat element. Heard that the scope of the variable in only inside the repeat tag. I want to load another div on the same page which need the details inside this var. How can I achieve this.
<ui:repeat var="errorDetails"
value="#{adminDashboardController.errorDetails}" varStatus="status">
<tr>
<td>#{errorDetails.issueName}</td>
<td>#{errorDetails.priority}</td>
<td>#{errorDetails.comments}</td>
<td><h:commandButton class="btn btn-primary btn-xs view-issue"
value="View" /></td>
</tr>
</ui:repeat>
<h4 class="modal-title" id="myModalLabel">#{errorDetails.issueName}</h4>
The errorDetails variable is only available in the scope of the ui:repeat.
You have here two options:
HTML/JS solution: Generate HTML code which contains one <h4...>#{errorDetails.issueName}</h4> for each line of your table and use JavaScript to display the right block when pressing on the command button.
I think that this option should be only used for performance reason, because you will generate lot of HTML and because as a JSF developer you usually prefer to avoid coding custom things in JavaScript.
JSF solution (my preferred one): use a backing bean to hold the currently viewed error detail. That would be something like this:
<ui:repeat var="errorDetails" value="#{adminDashboardController.errorDetails}" varStatus="status">
...
<h:commandButton ... action="#{adminDashboardController.showDetails(errorDetails)" update="myModalLabel" />
...
</ui:repeat>
...
<h:panelGroup rendered="#{adminDashboardController.currentDetail != null}">
<h4 class="modal-title" id="myModalLabel">#{adminDashboardController.currentDetail.issueName}</h4>
</h:panelGroup>
The AdminDashboardController.showDetails methods would save the given error detail in a the field currentDetail.

JSF update component from different form, boths forms with prependid false

Hi i have this sceneario, i have 2 forms each of them with preprendId=false, the first one have a h:panelGroup that i want to update from the second h:form. The problem that i have
is that i dont know what String i have to put for update my panelGroup. I tried with this strings:
panelGroupComboId and :panelGroupComboId
But i always get: Cannot find component with expression ":panelGroupComboId" referenced from...
Because i need to use preprendId=false at least in the first form (where my panelGroup is) i cannot set preprendIf=true, but if i did it i could update my component with any problem using: :loginFormRegistroId:panelGroupComboId
But remember i NEED to use preprendId= false, when i use preprendId=false i can see using
firebug that my h:panelGroup is converted as a div with the id panelGroupComboId, then thats why i dont how do i have to call for update it.
Is preprendId=true the only way to this works?
FIRST FORM
<h:form id="loginFormRegistroId" prependId="false">
<h:panelGroup id="panelGroupComboId" layout="block">
<select id="comboCarreraId" name="comboCarreraId" class="form-control">
<ui:repeat value="#{miBean.list}" var="obj">
<option value="#{obj.id}">#{obj.name}</option>
</ui:repeat>
</select>
</h:panelGroup>
</h:form>
SECOND FORM
<h:form prependId="false">
<p:remoteCommand
name="cargarCarrerasRemoteCommand"
process="#this"
actionListener="#{miBean.myListener}"
update="panelGroupComboId">
</p:remoteCommand>
</h:form>
By the way i DONT want to update the entire first FORM, just my h:panelGroup
Remove prependId from the forms. Update the code as
<h:form>
<p:remoteCommand
name="cargarCarrerasRemoteCommand"
process="#this"
actionListener="#{miBean.myListener}"
update=":loginFormRegistroId:panelGroupComboId">
</p:remoteCommand>
</h:form>

Javascript error in XHTML page in JSF 2

I have the following code in an xhtml page in JSF 2. But when the page loads I get an javascript error that
document.getElementById("country") is null or not an object.
Why is this happening?
<h:form>
<h:panelGrid columns="2">
Selected country locale :
<h:inputText id="country" value="#{country.localeCode}" size="20" />
Select a country {method binding}:
<h:selectOneMenu value="#{country.localeCode}" onchange="submit()"
valueChangeListener="#{country.countryLocaleCodeChanged}">
<f:selectItems value="#{country.countryInMap}" />
</h:selectOneMenu>
<script>
alert("hi");
document.getElementById("country").disabled=true;
</script>
</h:panelGrid>
</h:form>
It's not finding your component. Since your <h:inputText> is inside of an <h:form> the id will have the following pattern
formName:componentName. Since you did not specify an id for <h:form>, JSF will generate one for you. That's why you are seeing j_id1926454887_72d35e53:country where j_id1926454887_72d35e53 is the form id. If you want to deal with simpler id, then you should add an id value to your <h:form>. For example
<h:form id="form">
<h:inputText id="country" value="#{country.localeCode}" size="20" />
</h:form>
The id for <h:inputText> will now be form:country.
Even simpler, you could simply add prependId = "false" to your form
<h:form prependId="false">
and now your id for <h:inputText> will simply be country.
How can I get this id dynamically?
I'm going to modify your code slightly to achieve what you want (I'm thinking that you want to disable the input based on a specific event). Consider this simpler example
<h:form>
<h:inputText id="country" value="#{country.localeCode}" size="20" onclick="disableInputText(this.form)" />
</h:form>
Here I'm attaching a javascript function to an HTML DOM Event handler. In this case, I want the input to be disabled when I click on it (hence onclick). I'm also passing the form as a reference in the function. Then, define your Javascript like this.
<script>
function disableInputText(form) {
form[form.id + ":country"].disabled = true;
}
</script>
We simply grab the input in the javascript with the corresponding id via the object form and set its disabled attribute to true. (You can sort of view the form object as Map).
Also check the link below for more attributes of <h:inputText> and the different handlers you can use (the ones with on as prefix).
inputText Tag Attribute.
Also, check out the answer with the most votes to get a bigger picture on how ids are generated and other ways on how they can be determined.
How can I know the id of a JSF component so I can use in Javascript
It's seems to be a naming issue. the id of the field is not rendered as country.
i found a question that seems relevant. Composite components & ID

Issue in attribute for on h:outputLabel inside ui:repeat

I have following piece of code, i want to render radioButtons and labels for them. Due to the layout renderized by selectOneRadio and selectItem i decided to use plain HTML for the input radioButtons.
<h:panelGrid columns="6">
<ui:repeat value="#{myBean.list}" var="item">
<input id="#{item.innerList[0].id}" type="radio" name="radioItem" value="#{item.innerList[0].id}" />
<h:outputLabel for="#{item.innerList[0].id}" value="#{item.label}" />
</ui:repeat>
</h:panelGrid>
When trying to assign a label for them using outputLabel it renders the attribute for in HTML something like:
j_idt94:0:theidiassigned
The prependId flag in the tag form containing this code is set to false and in the documentation there is no such flag in the attributes of the other containing tags of the outputLabel.
The ui:repeat component is a NamingContainer. It controls the client identifier of its children.
The for attribute on a h:outputLabel will generally look for a component with a matching component identifier or client identifier.
So, for this markup:
<foo:someNamingContainer id="x">
<h:inputText id="foo" />
<h:outputLabel for="foo" />
</foo:someNamingContainer>
...the label would emit the matching, namespaced identifier <label for="...:x:foo".
There is no matching JSF component with a matching id since you are using a straight XHTML <input> element.
Consider just using a XHTML <label> element instead.

Resources