2

What I would like to achieve is to be able to address some JSF components from within other naming container.

Usecase: composite component which encapsulates some features using - for a field which is defined out of the composite component.

Some code:

<form id="foo">
...
<label for="nameTxt">Name:</label>
<component:customError forField="nameTxt" />
<h:inputText id="nameTxt" />
...
</form>

and the component:

<composite:implementation>
    <h:panelGroup id="errorComponent">
    ...
    <h:message for="#{cc.attrs.forField}" id="errorMsg" style="display:none;" />
    ...
    </h:panelGroup>
</composite:implementation>

The problem is that on rendering the message I get:

Could not render Message. Unable to find component 'nameTxt' (calling findComponent on component 'j_id963445801_469fc056:errorMsg')

I think I understand that the problem lies in the fact the the field "nameTxt" and the message "errorMsg" lie in other naming-containers. So what I would have and like to do is to specify the path/id of "nameTxt" in relation to some common ancestor.

After studying shortly the algorithm UIComponentBase:findComponent I do not actually see any other way of adressing cross naming-containers than by specyfing whole (absolute) id-path from the root (i.e. ":foo:...:nameTxt"). And this is both clumsy and prone for errors after changing the page structure.

So - how to address properly the field "nameTxt" from within the message in the composite component?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
jarek.jpa
  • 565
  • 1
  • 5
  • 18
  • What JSF impl/version are you using? I can't reproduce this on Mojarra 2.1.4 (also not on old 2.0.2). – BalusC Nov 16 '11 at 13:44
  • It's MyFaces 2.1.2. But if I'm not wrong, it comes directly from the resolution algorithm in findComponent, so meaby just another approach is needed here. But does it work for you? - i.e. you can reference other components with just plain id, no naming-container path? – jarek.jpa Nov 16 '11 at 13:50

1 Answers1

1

I can reproduce your problem on MyFaces 2.1.3, but not on Mojarra 2.1.4 (and also not on older Mojarra 2.0.2). This is likely a bug in MyFaces, you'd need to report it to the MyFaces guys. In the meanwhile, I don't see any other option than (temporarily) replacing the JSF implementation by Mojarra. It has however its own share of issues as well, mainly with its broken <ui:repeat> and partial state saving implementations.


Update: I found a workaround, it's however a bit clumsy:

<component:customError forField=":#{nameTxt.clientId}" />
<h:inputText id="nameTxt" binding="#{nameTxt}" />

This will lookup using the absolute client ID instead of relative client ID. You'd only need to remove style="display:none" from your <h:message> to solve a different matter.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • To the workaround: is the "binding" meaningful here? And I'm not sure whether it will work for paths where not every component is a naming container - I mean on the client path there will be all components, and the algorithm works only with ids of naming-containers. – jarek.jpa Nov 16 '11 at 14:07
  • For the implementation differences - thanks for the hint, it is not possible for me at the moment. Please say only HOW does it work for you on Mojarra - without any path (just id), or with path starting from some common ancestor? – jarek.jpa Nov 16 '11 at 14:09
  • Truly it is meaningful, else the workaround won't work. It binds the component as `UIComponent` (http://download.oracle.com/javaee/6/api/javax/faces/component/UIComponent.html) to the view so that you can reference it elsewhere by EL in the same view like as in `forField` in the example in my answer. It basically passes `":" + component.getClientId()` to the composite. Re: Mojarra, just the same way as you initially did and intuitively expected to work: `forField="nameTxt"` and `for="#{cc.attrs.forField}`. – BalusC Nov 16 '11 at 14:10
  • OK, I see it now. And contrary to my comment above, it should work for all paths - as the only elements in client id path, are the ids of the naming-containers (with the exception only of containers with explicit prependId=false). Thanks for the workaround and interesting discussion.. – jarek.jpa Nov 16 '11 at 14:32
  • PS. the style="display:none;" is intentionally there :) – jarek.jpa Nov 16 '11 at 14:35