Reference dynamic Id in JSF composite components - jsf

I've been having some trouble to reference Id with composite components in JSF like the example:
`<composite:interface>
<composite:attribute name="id" required="true"/>
</composite:interface>
<composite:implementation>
<h:inputText id="#{cc.attrs.id}" value="Any"
</composite:implementation>
`
And when I try to pass the Id as param, I can't reference it from a "for" for example from an outputLabel, it seems this kind of composite components in JSF does not support dynamic Ids, what is the solution for it?
Thanks in advance.

Related

How to reference component inside a composite component when using a converter

I have a composite component that mainly consists of a selectManyCheckbox component. As it should be designed in a generic way I pass in selectItems, ajax handling etc. from the calling level using
<composite:insertChildren/>
This works quite well for most of the stuff. Now I need to use this composite component with a converter. As the converter (a kind of Omnifaces' ListConverter) is not needed all the time (sometimes I want to have the value-binding of concrete entities that back the select items, sometimes I don't), I'd like to pass it in as the parts mentioned before (e.g. selectItems, ajax event handling).
Given this it is necessary to use the converter tag's 'for' attribute to reference the component inside the composite component. At least that is what I understand.
Unfortunately I have no idea what value should be used. Do I have to include the name of the composite component (naming container)? Do I have to use the clientId? I have tried a lot of combinations but the converter has not been invoked. As soon as I put the converter tag inside the composite component definition, it works.
To make things easier, let's assume I have the following:
<composite:interface>
<composite:attribute name="value" required="true"/>
</composite:interface>
<composite:implementation>
[...]
<h:selectManyCheckbox id="#{cc.attrs.id}" value="#{cc.attrs.value}">
<composite:insertChildren/>
</h:selectManyCheckbox>
[...]
</composite:implementation>
This component should be used as follows:
<my:selectManyCheckbox id="myComponent" value="...">
<f:selectItems value="..."/>
<o:converter for="___" converterId="..."/>
</my:selectManyCheckbox>
Perhaps someone can give me a hint what value should be given to the 'for' attribute.
I found the answer myself. You can use the following
<composite:interface>
<composite:attribute name="value" required="true"/>
<composite:editableValueHolder name="input_component">
</composite:interface>
<composite:implementation>
[...]
<h:selectManyCheckbox id="input_component" value="#{cc.attrs.value}">
<composite:insertChildren/>
</h:selectManyCheckbox>
[...]
</composite:implementation>
The important part is the editableValueHolder tag. From the page using this composite component, you can now use
<o:converter for="input_component" converterId="id_of_converter" />
This is the solution that is working for me. I hope this helps others having the same problem.

How to detach variable from the backing bean in JSF?

I'm in a situation, where I need to pass a variable to some dialog(in custom tag component), the field with the value should be editable, but the dialog shouldn't be able to modify the original value in the managed bean.
This is how I call the component:
<my:aerodromeSelection value="#{fpl.adepIcaoId}" id2="adep"/>
This is fragment of the composite component(only relevant parts included):
<composite:interface>
<composite:attribute name="id2" required="true"/>
<composite:attribute name="value" required="true"/>
</composite:interface>
<composite:implementation>
<p:panelGrid>
<p:commandButton icon="ui-icon-search" update="#{cc.attrs.id2}_dialog" oncomplete="#{cc.attrs.id2}_dialogAerodrome.show()"/>
</p:panelGrid>
<p:dialog widgetVar="#{cc.attrs.id2}_dialogAerodrome" dynamic="true">
<p:panelGrid>
<p:inputText value="#{cc.attrs.value.icaoCode}"/>
</p:panelGrid>
</p:dialog>
</composite:implementation>
After clicking the button, the dialog is shown and I can edit the value. The problem is, that I don't want the value to be set to the original variable.
I tried setting the value to the managed bean of the custom component and use those values instead, but if I do it like this, then having multiple dialogs in one page, I always get the value of the last one:
<c:set value="#{cc.attrs.value.icaoCode}" target="#{adSearchBB}" property="icaoCode"/>
So I need to solve one of two problems:
Why is the value in the adSearchBB(RequestScoped, but I've also tried ViewScoped) shared among all dialogs
How to "unbind" the variable passed to custom component
Also, what should be the scope of the managed bean? I'd ideally want one bean per component.
I'm using
Primefaces 3.5
Apache MyFaces 2.1.10

What is f:attribute used for in this example?

I'm trying to understand what a JSF snippet does. It goes something like this
<composite:interface>
<composite:attribute name="field" />
<composite:attribute name="value" default=""/>
[...]
</composite:interface>
<composite:implementation>
<ui:fragment rendered="some_logic_here">
<h:outputText value="#{cc.attrs.value}">
<f:attribute name="value" value="#{cc.attrs.field.value}"/>
</h:outputText>
</ui:fragment>
</composite:implementation>
The field attribute refers to a bean member that has getValue() / setValue() accessors (for a string).
The value attribute is a string that comes from elsewhere.
From what I understand, the output's value is initially set to the (static) value attribute: value="#{cc.attrs.value}", then the <f:attribute> tag sets something to the "dynamic" value retrieved from the "field" bean.
How does this work out? Does the "dynamic" value override the static one? Always?
As you guessed, this does indeed exactly the same as:
<h:outputText value="#{cc.attrs.field.value}" />
In other words, the original developer didn't thought out it very well, or was fiddling until it started to work like magic, or perhaps had a short on coffee, or smoked something bad while developing.

How to create a composite component which switches between inputText and inputSecret?

I'm writing a Facelets composite component that switches between using inputText and inputSecret based on a parameter:
<composite:interface>
<composite:attribute name="myId" required="true"/>
<composite:attribute name="secret" required="false" default="false" />
</composite:interface>
<composite:implementation>
<h:inputSecret rendered="#{cc.attrs.secret}" id="#{cc.attrs.myId}" />
<h:inputText rendered="#{!cc.attrs.secret}" id="#{cc.attrs.myId}" />
</composite:implementation>
The problem is that I get the following error:
Component ID [JSF mangled id] has already been found in the view.
Use a view build time tag like JSTL <c:if> or <c:choose> instead of the JSF component's rendered attribute. View build time tags are evaluated during constructing the JSF component tree, while the rendered attribute is only evaluated during generating HTML based on the JSF component tree (and thus you still end up with both components with the same ID in the JSF component tree!).
E.g.
<c:if test="#{not cc.attrs.secret}">
<h:inputText id="input" />
</c:if>
<c:if test="#{cc.attrs.secret}">
<h:inputSecret id="input" />
</c:if>
See also:
JSTL in JSF2 Facelets... makes sense?
Unrelated to the concrete problem, the myId doesn't make sense. Just give those a fixed ID. In case the reason was the inability to reference them from outside by ajax, head to Referring composite component ID in f:ajax render.
Whether or not the component is actually rendered doesn't matter.Both components will still exist in the view's internal component tree and will require a unique id. We ran into this problem as well.
We suffixed the id with a _1 and _2 and if we need to get a hold of the id inside javaScript, we use JQuery's partial matchers.
In your case, can you not make your bean's getMyId() method return a different id based on the value of the secret property?

JSF 2 composite component, passing attributes to backing bean

I'm stuck on simple JSF2 question:
XHTML:
<xvf:simpleOut identifier="12345"/>
Composite component is supposed to pass "12345" to backing bean and do some output:
<composite:interface>
<composite:attribute name="identifier" required="true" type="java.lang.String"/>
</composite:interface>
<composite:implementation>
<!--#elvariable id="arg" type="java.lang.String"-->
<ui:param name="arg" value="#{cc.attrs.identifier}"/>
<h:outputText value="#{myBean.getTestOutput('???????')}"/>
</composite:implementation>
How do I pass identifier value, '12345' in my case, to bean's getTestOutput(String arg) method?
You don't need the <ui:param> tag at all. This should work:
<h:outputText value="#{myBean.getTestOutput(cc.attrs.identifier)}"/>
But it might a a good idea to pass myBean through the interface as well rather than refering to it directly, since it would make the composite component reusable.

Resources