Composite components & ID - jsf

I want to implement some javas cript into my JSF composite component, but I have problem with id. My java script with:
document.getElementById("myForm:customerId")
does not work, because the id is wrong. I have JSF composite component:
<composite:implementation>
<div id="element_customer">
<h2 class="element_title">Customer</h2>
<h:form id="myForm">
<h:inputText id="customerId" value="#{cc.attrs.customerId}"/>
</h:form>
</div>
</composite:implementation>
and HTML output is:
<div id="element_customer">
<h2 class="element_title">Customer</h2>
<form id="j_idt44:myForm" name="j_idt44:myForm" method="post" ... >
<input type="hidden" name="j_idt44:myForm" value="j_idt44:myForm" />
<input id="j_idt44:myForm:customerId" ... name="j_idt44:myForm:customerId" />
</form>
</div>
Why is "j_idt44" used in HTML output?

Composite components are NamingContainer components like <h:form>, <h:dataTable>, etc. This allows you to have multiple of them in the same view without conflicting IDs.
You need to give the composite component a fixed ID as well. E.g.
<my:composite id="someId" />
I'd also suggest to use <div id="#{cc.id}"> instead of <div id="element_customer">. It will then become someId with the above example.
Unrelated to the concrete problem, this isn't entirely the right purpose of a composite component. A composite component is intented to be of the same kind of <h:inputText>, etc. You seem to rather want a tag file or maybe an include file. See also When to use <ui:include>, tag files, composite components and/or custom components?

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.

Control generated ID of ui:repeat

Sorry for the simple question. I am learning to use JSF 2.2 to create a form and trying to keep it close to plain HTML5 as possible. I have an ui:repeat generated list that goes like this:
<ul id="nameLst">
<ui:repeat var="d" value="#{controller.names}" varStatus="status">
<li>
<input
jsf:id="nameTxt"
jsf:binding="#{nameTxt}"
jsf:value="#{d}"
type="hidden" />#{d}
</li>
</ui:repeat>
</ul>
It gets rendered like this:
<ul id="nameLst">
<li>
<input id="j_idt14:0:nameTxt" name="j_idt14:0:nameTxt" value="Name1" type="hidden">
Name1
</li>
<li>
<input id="j_idt14:1:nameTxt" name="j_idt14:1:nameTxt" value="Name2" type="hidden">
Name2
</li>
</ul>
Now, I am trying to add names using JavaScript only to this list. Problem is, how can I control this generated id, so I can use it in JavaScript. And mainly, if the list starts empty, how do I generate this id so it can be correctly posted back to the managed bean.
how can I control this generated id, so I can use it in JavaScript
Just give it a fixed id.
<ui:repeat id="names" ...>
Alternatively, use jsfc attribute to turn <ul> into an <ui:repeat>.
<ul id="names" jsfc="ui:repeat" value="#{bean.names}" var="name">
<li>
<input jsf:id="name" type="hidden" value="#{name}" />
</li>
</ul>
And mainly, if the list starts empty, how do I generate this id so it can be correctly posted back to the managed bean
Use JSF for this instead of JS. An example can be found here: How to dynamically add JSF components
See also:
How can I know the id of a JSF component so I can use in Javascript
JavaServer Faces 2.2 and HTML5 support, why is XHTML still being used

JSF commandButton - passing POST params to an external site

I need a link which redirect me to a different site and send POST parameters. Something like:
<h:form>
<h:commandButton value="submit" action="http://example.com">
<f:param name="user" value="robson">
</h:commandButton>
</h:form>
The code above doesn't work of course.
I'd like to acheive this in HTML:
<form action="http://example.com" method="POST">
<input type="hidden" name="user" value="robson">
<input type="submit" value="submit">
</form>
Is that possible?
Use the vanilla HTML <form> tag, not the JSF tag if you're going to send form data to a non-JSF target.
The JSF form tag is designed to facilitate JSF postback operations, which is why it has no "action" attribute.

Seam / RichFaces + forceId

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!

Calling servlet post from jsf in different war

I want to call a Servlet which exists in a different war from my war. When user clicks a button we need to call the post method of the servlet. To implement this I did see an existing example which is slightly different but works in that case.
I am using jsf, so in the jsp there is a h:form with another html form inside of it. Below is the code:
<h:form>
<div id="gform" class="column span-20 append-1">
<h:outputText value="Text." /><br/><br/>
<h:commandLink id="addPaymentButton" styleClass="button" onclick='autorenew();return false;'> <span><h:outputText value="Payment Option"/></span> </h:commandLink>
<a id="noThanksButton" href="#"><span><h:outputText value="No Thanks"/></span></a><br/><br/><br/>
<h:outputText style="color:grey" value="Some text" />
<div> </div>
</div>
<form id="hiddenSubmit" method="post" action="https://localhost.myapp.com/myapp/LoginRouter" >
<input type="hidden" name="redirectUrl" value="/myapp/customers/addNewSavedCCInfo.faces"/>
<input type="hidden" name="jump_message" value="IAmJumpingToCC"/>
<input type="hidden" name="jump_url" value="/premiumServices/myPage.htm"/>
<input id="hiddenSubmitButton" type="submit" name="submit" style="display: none" value='' />
</form>
</h:form>
<script language="javascript">
function autorenew(){
window.alert('In js fnt');
document.hiddenSubmit.getElementById('hiddenSubmitButton').click();
window.alert('In js fnt COMPLETE');
return false;
}
So when the button is clicked, javascript is executed which submits the form to the servlet. However I can see in firebug that the second form which I need to submit does not appear. I am not sure how I can call the post method of a servlet class in a different war. Any ideas welcome, I am really stuck!
Thanks.
As per the HTML specification it's forbidden to nest <form> elements. The (mis)behaviour is browser dependent. Some browsers will send all parameters, some browsers will send only the data of the parent form, other browsers will send nothing.
You want to have a single form here. You can perfectly replace the <h:form> by a plain vanilla HTML <form> with the desired action pointing to the servlet in question.

Resources