How can I know the id of a JSF component so I can use in Javascript
Asked Answered
C

6

48

Problem: Sometimes you will want to access a component from javascript with getElementById, but id's are generated dynamically in JSF, so you need a method of getting an objects id. I answer below on how you can do this.


Original Question: I want to use some code like below. How can I reference the inputText JSF component in my Javascript?

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
    <head>
       <title>Input Name Page</title>
        <script type="javascript" >
          function myFunc() {
            // how can I get the contents of the inputText component below          
            alert("Your email address is: " + document.getElementById("emailAddress").value);
          }
       </script>
    </head>
    <h:body>
        <f:view>
            <h:form>
                Please enter your email address:<br/>
                <h:inputText id="emailAddresses" value="#{emailAddresses.emailAddressesStr}"/>
                <h:commandButton onclick="myFunc()" action="results" value="Next"/>
            </h:form>
        </f:view>
    </h:body>
</html>

Update: this post Client Identifiers in JSF2.0 discusses using a technique like:

<script type="javascript" >
  function myFunc() {
    alert("Your email address is: " + document.getElementById("#{myInptTxtId.clientId}").value);
  }
</script>

<h:inputText id="myInptTxtId" value="backingBean.emailAddress"/>
<h:commandButton onclick="myFunc()" action="results" value="Next"/>

Suggesting that the attribute id on the inputText component creates an object that can be accessed with EL using #{myInptTxtId}, in the above example. The article goes on to state that JSF 2.0 adds the zero-argument getClientId() method to the UIComponent class. Thereby allowing the #{myInptTxtId.clientId} construct suggested above to get the actual generated id of the component.

Though in my tests this doesn't work. Can anyone else confirm/deny. The answers suggested below suffer from drawback that the above technique doesn't. So it would be good to know if the above technique actually works.

Chickadee answered 18/5, 2011 at 13:16 Comment(0)
C
6

Answer: So this is the technique I'm happiest with. Doesn't require doing too much weird stuff to figure out the id of a component. Remember the whole point of this is so you can know the id of a component from anywhere on your page, not just from the actual component itself. This is key. I press a button, launch javascript function, and it should be able to access any other component, not just the one that launched it.

This solution doesn't require any 'right-click' and see what the id is. That type of solution is brittle, as the id is dynamically generated and if I change the page I'll have to go through that nonsense each time.

  1. Bind the component to a backing bean.

  2. Reference the bound component wherever you want.

So here is a sample of how that can be done.

Assumptions: I have an *.xhtml page (could be *.jsp) and I have defined a backing bean. I'm also using JSF 2.0.

*.xhtml page

<script>
  function myFunc() {
    var inputText = document.getElementById("#{backBean.emailAddyInputText.clientId}")                 
    alert("The email address is: " + inputText.value );
  }
</script>

<h:inputText binding="#{backBean.emailAddyInputText}"/>
<h:commandButton onclick="myFunc()" action="results" value="Next"/>

BackBean.java

UIInput emailAddyInputText;

Make sure to create your getter/setter for this property too.

Chickadee answered 20/5, 2011 at 7:3 Comment(1)
Binding the component to the bean is totally unnecessary and only adds clutter to the bean. Just bind to the view directly as in the first part of my answer update.Cirrocumulus
C
60

You need to use exactly the ID as JSF has assigned in the generated HTML output. Rightclick the page in your webbrowser and choose View Source. That's exactly the HTML code which JS sees (you know, JS runs in webbrowser and intercepts on HTML DOM tree).

Given a

<h:form>
    <h:inputText id="emailAddresses" ... />

It'll look something like this:

<form id="j_id0">
    <input type="text" id="j_id0:emailAddress" ... />

Where j_id0 is the generated ID of the generated HTML <form> element.

You'd rather give all JSF NamingContainer components a fixed id so that JSF don't autogenerate them. The <h:form> is one of them.

<h:form id="formId">
    <h:inputText id="emailAddresses" value="#{emailAddresses.emailAddressesStr}"/>

This way the form won't get an autogenerated ID like j_id0 and the input field will get a fixed ID of formId:emailAddress. You can then just reference it as such in JS.

var input = document.getElementById('formId:emailAddress');

From that point on you can continue using JS code as usual. E.g. getting value via input.value.

See also:


Update as per your update: you misunderstood the blog article. The special #{component} reference refers to the current component where the EL expression is been evaluated and this works only inside any of the attributes of the component itself. Whatever you want can also be achieved as follows:

var input = document.getElementById('#{emailAddress.clientId}');

with (note the binding to the view, you should absolutely not bind it to a bean)

<h:inputText binding="#{emailAddress}" />

but that's plain ugly. Better use the following approach wherein you pass the generated HTML DOM element as JavaScript this reference to the function

<h:inputText onclick="show(this)" />

with

function show(input) {
    alert(input.value);
}

If you're using jQuery, you can even go a step further by abstracting them using a style class as marker interface

<h:inputText styleClass="someMarkerClass" />

with

$(document).on("click", ".someMarkerClass", function() {
    var $input = $(this);
    alert($input.val());
});
Cirrocumulus answered 18/5, 2011 at 13:18 Comment(6)
Alternatively you can set the <h:form prependId="false"> and the form id will not prepend itself to your DOM elements.Verbify
@maple: You only need to be careful with duplicate ids. For simple forms like this you can indeed do as such. But for complex pages with repeating components in the view, you'd like to leave it default.Cirrocumulus
My main goal was intercomponent communication so to speak. Your solution doesn't allow clicking a button and that firing javascript that accesss any other component in your page. See my answer below for a better solution.Chickadee
Why are you binding this to the backing bean? That's only clutter. Just bind to the view immediately as in the first part of my answer update.Cirrocumulus
@Cirrocumulus Although I am giving fixed id called speak out to my p:commandButton, it is still auto generating an id called id="j_idt39:speakout"Christeenchristel
@AmlanKarmakar You need to give a fixed ID to the naming container that contains speakout.Inductive
C
6

Answer: So this is the technique I'm happiest with. Doesn't require doing too much weird stuff to figure out the id of a component. Remember the whole point of this is so you can know the id of a component from anywhere on your page, not just from the actual component itself. This is key. I press a button, launch javascript function, and it should be able to access any other component, not just the one that launched it.

This solution doesn't require any 'right-click' and see what the id is. That type of solution is brittle, as the id is dynamically generated and if I change the page I'll have to go through that nonsense each time.

  1. Bind the component to a backing bean.

  2. Reference the bound component wherever you want.

So here is a sample of how that can be done.

Assumptions: I have an *.xhtml page (could be *.jsp) and I have defined a backing bean. I'm also using JSF 2.0.

*.xhtml page

<script>
  function myFunc() {
    var inputText = document.getElementById("#{backBean.emailAddyInputText.clientId}")                 
    alert("The email address is: " + inputText.value );
  }
</script>

<h:inputText binding="#{backBean.emailAddyInputText}"/>
<h:commandButton onclick="myFunc()" action="results" value="Next"/>

BackBean.java

UIInput emailAddyInputText;

Make sure to create your getter/setter for this property too.

Chickadee answered 20/5, 2011 at 7:3 Comment(1)
Binding the component to the bean is totally unnecessary and only adds clutter to the bean. Just bind to the view directly as in the first part of my answer update.Cirrocumulus
P
5

Id is dynamically generated, so you should define names for all parent elements to avoid j_id123-like ids.

Note that if you use jQuery to select element - than you should use double slash before colon:

    jQuery("my-form-id\\:my-text-input-block\\:my-input-id")

instead of:

    jQuery("my-form-id:my-text-input-block:my-input-id")

In case of Richfaces you can use el expression on jsf page:

    #{rich:element('native-jsf-input-id')} 

to select javascript element, for example:

    #{rich:element('native-jsf-input-id')}.value = "Enter something here";
Plump answered 18/5, 2011 at 16:21 Comment(0)
S
0

You can view the HTML source when this is generated and see what the id is set to, so you can use that in your JavaScript. As it's in a form it is probably prepending the form id to it.

Stephanotis answered 18/5, 2011 at 13:20 Comment(1)
The id is auto-generated.Flavour
S
0

I know this is not the JSF way but if you want to avoid the ID pain you can set a special CSS class for the selector. Just make sure to use a good name so that when someone reads the class name it is clear that it was used for this purpose.

<h:inputText id="emailAddresses" class="emailAddressesForSelector"...

In your JavaScript:

jQuery('.emailAddressesForSelector');

Of course you would still have to manually manage class name uniqueness. I do think this is maintainable as long as you do not use this in reusable components. In that case you could generate the class names using a convention.

Schizopod answered 10/5, 2013 at 13:32 Comment(2)
It should be easy to find the element with jQuery selector. But for me it looks like colon in the ID (which I believe is not allowed) messes it up causing selector not to work: https://mcmap.net/q/18042/-jquery-selector-id-ends-withBayer
@PanuHaaramo you can escape special charactersSchizopod
M
-1
<h:form  id="myform">
 <h:inputText  id="name" value="#{beanClass.name}" 
                a:placeholder="Enter Client Title"> </h:inputText>
</h:form>

This is a small example of jsf. Now I will write javascript code to get the value of the above jsf component:

    var x = document.getElementById('myform:name').value; //here x will be of string type

   var y= parseInt(x,10); //here we converted x into Integer type and can do the 
                           //arithmetic operations as well
Marilumarilyn answered 11/12, 2018 at 17:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.