Seam / RichFaces + forceId - jsf

I'm having trouble with a4j:repeat and it's id generation. Every element inside the loop has it's id preceded with a unique identifier. I don't want this. I want certain elements to contain the id that I present them (I'm ensuring they're unique).
I've search around and it looks like Tomahawk tags have an attribute forceId which will cause the element to use the id provided. The only thing is, it looks like it's not recommended to use Tomahawk tags with Seam / RichFaces.
Is there anything similar in anyone of the tag libraries recommended to be used with Seam? Barring that, is it reasonably feasible for me to subclass a4j:repeat (or possibly even ui:repeat) and change the way it handles id generation?
Any ideas? All I need is a way to loop through elements giving them dynamic ids.

This is not a RichFaces problem. It is JSF. JSF adds a unique id to each components. This is a known JSF feature.
However, there is something you can do.
In your <h:form> you can set prependId="false". This will tell JSF not to add any ID's from each component.
(Also make sure you are not using s:decorate="/layout/template.xhtml because the template.xhtml and edit.xhtml will add id's of their own.
So do something like this:
<h:form prependId="false">
<a4j:repeat value="#{foo}" var="f" rowKeyVar="row">
<h:inputText id="unique#{row}"/>
</a4j:repeat>
</h:form>
This will make the id like this: unique1 unique2 unique3 etc
Update
Seems you are right. For some reason, the id tag doesn't support this type of EL expression.
I tried the following:
<a:repeat id="table" value="#{foo}" var="k" rowKeyVar="row">
<h:inputText id="test#{row}" value="row is #{row}" styleClass="test#{row}"/><br/>
</a:repeat>
And it produces the generated html
<input type="text" class="test0" value="row is 0" name="table:0:test" id="table:0:test">
<input type="text" class="test1" value="row is 1" name="table:1:test" id="table:1:test">
<input type="text" class="test2" value="row is 2" name="table:2:test" id="table:2:test">
So as you can see, I still get a unique id because. Probably is adding the number for me automatically.
It doesn't matter if you add or not. The result is the same.

Maybe useful: You can get real ids in JSF (RichFaces) with #{rich:clientId('id')}. So you can use the generated id in JS.

I don't know why you wouldn't let JSF do the ID generation for you, but I understand that it isn't easy to figure out, since JSF has very little documentation on this subject in my opinion.
I'll tell you my findings on this subject by giving an example (using JSF 2.0.3 Mojarra by the way):
<h:form id="myForm">
<ui:repeat id="loopzor" var="#{myItem}" value="#{myController.myList}">
<h:outputLabel for="myName" value="#{labels.name}:" />
<h:inputText id="myName" value="#{myItem.name}" />
</ui:repeat>
<h:selectOneMenu id="type" value="#{address.type.id}">
<f:selectItems value="#{types}" var="type" itemLabel="#{type.label}" itemValue="#{type.id}"/>
</h:selectOneMenu>
<h:inputText id="value" value="#{address.value}"/>
</h:form>
This is a typical example of how a form might look like. This is what happens when the page is rendered with a list size of 2 items:
<form id="myForm">
<label for="myForm-loopzor-0-myName">Name:</label>
<input id="myForm-loopzor-0-myName" type="text" value="someName" />
<label for="myForm-loopzor-1-myName">Name:</label>
<input id="myForm-loopzor-1-myName" type="text" value="someName2" />
<select id="myForm-type" name="myForm-type>
<option value="1" selected="selected">Label1</option>
<option value="2" >Label2</option>
</select>
</form>
So the ID generation is as follows:
Give IDs to all h:form elements, this will prefix all elements in this form with this ID
If you don't want the form ID prefixed to each element, add the attribute prependid="false" to the h:form element
Give IDs to all ui:repeat elements (even though the id attribute is not specified in the specs)
Give IDs to all h:inputText and other input elements, even inside ui:repeat elements they will get a unique ID based on their position in the loop
You can give IDs to f:selectItems elements but they will not be taken into account
You can suffix the IDs with the varStatus object but this will always return an empty string, probably because when generating the dynamic IDs the varStatus object does not exist
I hope this can clear out some of the confusions about ID generation!

Related

JSF id value to the component behaves different

I have the following code in my xhtml
<h:form id="xyForm">
<p:dataGrid id="xyGrid" ....>
<p:selectOneMenu id="code" ...> </p:selectOneMenu>
</p:dataGrid>
</h:form>
But when I saw the code generated, it looks like the following
<select name="xyForm:xyGrid:0:code_input" tabindex="-1" id="xyForm:xyGrid:0:code_input"> </select>
My question here is: why _input is getting appended with name and id.
As per my understanding id should be only xyForm:xyGrid:0:code not with appended _input. Could someone please clarify or tell me how to remove that _input?
An id attribute should be unique within an html page.
While rendering the SelectOneMenu, the select tag is wrapped inside a div tag. The div tag will have the id of the component i.e. xyForm:xyGrid:0:code, and so it makes sense that the select tag should have a different id.
Also, this is a common pattern in Primefaces, observed in other components like SelectBooleanCheckbox etc.
Instead of trying to removing _input, you will have to figure around how to work around it.

Unable to find component for ID in view

In a JSF, Primefaces 6 project, I get the following warning:
Unable to find component for ID dateFrom_input in view
Here is the view:
<h:outputLabel for="dateFrom_input" />
<p:autoComplete id="dateFrom" ...></p:autoComplete>
p:autoComplete is replaced by:
<span id="searchForm:dateFrom">
<input id="searchForm:dateFrom_input" name="searchForm:dateFrom_input" type="text" autocomplete="off">
...
</span>
Basically, I have to set the label for component dateFrom_input to get the feature working (I mean clicking on label to jump in the field...). It works but the warning appear.
It looks I cannot make reference to something in a widget...
How two shut this warning up?
UPDATE
In a DOM point of view, what I do is correct (label for parameter set with the input ID). But in a JSF point of view, p:autocomplete field is not yet "compiled" as HTML and it cannot reach the input (which effectively take ID dateFrom_input once compiled)
Please try to use the following:
<p:outputLabel for="dateFrom" value="Click here! "/>
<p:autoComplete id="dateFrom" ...></p:autoComplete>

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

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

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.

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