Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving other component's client ID in JSF 2.0

Does JSF 2.0 have a built-in method for finding the client ID of another component? There are about a thousand client ID-related questions on SO and there are a lot of hackish methods to do this, but I'm wondering if JSF 2.0 brought a simpler method that I just don't know.

#{component.clientId} evaluates to a given component's own client ID, but I want to reference another component's ID.

This blog post mentions component.clientId, and it also says #{someComponent.clientId} works, but from what I can tell it does not. I believe he wrote that before any reference implementations of JSF 2.0 were out, so he was just going by the JSR and maybe that functionality changed. I'm not sure.

I know PrimeFaces and RichFaces both have their own functions to return a client ID, but I'm just wondering if there's a built-in JSF 2.0 method for this. Here are some examples:

This works to return the outputText's ID.

`<h:outputText value="My client ID : #{component.clientId}" />`

According to the blog post above, this should work, but it does not. I just get no output.

`<h:button id="sampleButton" value="Sample" />`

`<h:outputText value="sampleButton's client ID : #{sampleButton.clientId}" />`

This works in PrimeFaces:

`<h:outputText value="PrimeFaces : sampleButton's client ID : #{p:component('sampleButton')}" />` 

Works in RichFaces:

`<h:outputText value="RichFaces : sampleButton's client ID : #{rich:clientId('sampleButton')}" />`

Also, if at all possible I'm looking for solutions that won't break if I change the javax.faces.SEPARATOR_CHAR value or if I add/remove containers outside the referenced components. I've spent plenty of time tracking down issues caused by hard-coded ID paths.

like image 559
cutchin Avatar asked Aug 25 '12 18:08

cutchin


3 Answers

You need to assign the component a variable name in the view scope by binding attribute.

<h:button id="sampleButton" binding="#{sampleButton}" value="Sample" />
<h:outputText value="sampleButton's client ID : #{sampleButton.clientId}" />
like image 189
BalusC Avatar answered Oct 16 '22 21:10

BalusC


This worked for me. I would be interested to know if it is Ok to write response like this though.

client.html

<h:outputText value="#{UIHelper.clientId('look-up-address-panel-id')}" />

UIHelper.java

@ManagedBean(name = "UIHelper", eager = true)
@ApplicationScoped
public class UIHelper
{

public String clientId(final String id)
{
  FacesContext context = FacesContext.getCurrentInstance();
  UIViewRoot root = context.getViewRoot();
  final UIComponent[] found = new UIComponent[1];
  root.visitTree(new FullVisitContext(context), new VisitCallback()
  {
    @Override
    public VisitResult visit(VisitContext context, UIComponent component)
    {
      if (component.getId().equals(id))
      {
        found[0] = component;
        return VisitResult.COMPLETE;
      }
      return VisitResult.ACCEPT;
    }
  });
  return found[0] == null ? "" : "#" + found[0].getClientId().replace(":", "\\\\:");
}

}
like image 28
mert inan Avatar answered Oct 16 '22 21:10

mert inan


Since this was among the first results of my google search and I wondered why I got a

javax.el.PropertyNotFoundException (Property 'itemId' not found [...])

when trying the accepted solution, I would like to share my solution for JSF 1.2:

The UIComponent's method getClientId needs a FacesContext parameter (see UIComponent documentation). So add a binding to the backing bean and also another method that returns the clientId:

xhtml:

<h:button id="sampleButton" binding="#{backingBean.sampleButton}" value="Sample" />
<h:outputText value="sampleButton's client ID : #{backingBean.sampleButtonClientId}" />

Bean:

private UIComponent sampleButton;

public UIComponent getSampleButton() {
    return sampleButton;
}

public void setSampleButton(final UIComponent sampleButton) {
    this.sampleButton = sampleButton;
}

public String getSampleButtonClientId() {
    final FacesContext context = FacesContext.getCurrentInstance();
    return sampleButton.getClientId(context);
}

Notice that the bean you are binding your component to should be request scoped or else you could end up with a java.lang.IllegalStateException (duplicate Id for a component) (compare to this topic).

like image 29
david Avatar answered Oct 16 '22 21:10

david