Updated 2009/11/24
This post is obsolete; go read this one instead: JSF: working with component identifiers The approach described in this post may fail if the component identifiers are not unique within the view.
I've written about how to use a custom function to get the clientId
before.
You can download the code from here.
Below is an example that uses the id:cachedClientId
function in a data table. I'm using Facelets, so you can't just
cut and paste the code into a JSP. However, the principle is the same.
The page lists a number of products and lets you set the fields to default values using JavaScript. Not a brilliant example, but it will suffice.
The Facelets page:
<?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:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:id="http://illegalargumentexception.googlecode.com/clientId"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>clientIdTest</title> </head> <body> <h:form> <h:dataTable value="#{dataBean.rows}" var="row"> <h:column> <h:outputText value="#{row.product}" /> </h:column> <h:column> <h:inputText id="qtty" value="#{row.quantity}" /> </h:column> <h:column> <button onclick="setQuantity('#{id:cachedClientId('qtty')}', #{row.defaultQuantity}); return false"> Set as #{row.defaultQuantity}</button> </h:column> </h:dataTable> <h:commandButton value="order" action="#{dataBean.order}" /> </h:form> <script type="text/javascript"> function setQuantity(elementId, n) { var textField = document.getElementById(elementId); textField.value = n; return false; } </script> </body> </html>
The demo table is backed by by this session bean:
/* |
Here is the row definition:
public class RowBean implements Serializable { |
How does that work?
Here is how the HTML table rows are rendered:
<tr> <td> Product 4 </td> <td> <input id="j_id2:j_id3:4:qtty" name="j_id2:j_id3:4:qtty" type="text" value="4" /> </td> <td> <button onclick="setQuantity('j_id2:j_id3:4:qtty', 4); return false"> Set as 4</button> </td> </tr>
The clientId
of the text field (id=qtty
)
is managed by its parent naming
containers (e.g. UIData).
The data table will change the clientId of its children before each row
is rendered. Because the caching mechanism in the expression #{id:cachedClientId('qtty')}
caches the path to the component and not the clientId
value, it returns the correct value each time.
How to screw things up
Here is an example of how not to refer to the clientId
.
Here, we try to rewrite the Facelet to insert the ID directly into the
JavaScript:
<script type="text/javascript"> function setQuantity(n) { var textField = document.getElementById('#{id:cachedClientId('qtty')}'); textField.value = n; return false; } </script>
However, this does not work! This is what is rendered to the page:
<script type="text/javascript"><!-- function setQuantity(n) { var textField = document.getElementById('j_id2:j_id3:qtty'); textField.value = n; return false; } //--></script>
The HTML element ID j_id2:j_id3:qtty
does not match
any of the text fields (which look have clientIds of the form j_id2:j_id3:N:qtty
).
The expression is not being evaluated in the context of any of the rows.
It is an error to use the expression #{id:cachedClientId('qtty')}
outside the table that controls that component.
Notes
I used Apache MyFaces 1.2.3 and Facelets 1.1.14 running on Tomcat 6 under Java 6.
Hi, I'm using a table that has a column of textfields. When the user clicks a button, I want to retrieve the new values from each field. I know the client ID of the components, however I can't find them in my bean. Do you know how to do this?
ReplyDeleteThanks
That's kind of vague - I suggest you post a question on stackoverflow.com (or some similar site) with more details.
ReplyDelete