What is f:attribute used for in this example? - jsf

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.

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.

Reference dynamic Id in JSF composite components

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.

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?

Pass actionListener method to commandButton within a component

first, please forgive my ignorance and inability so use the search engine (i swear i have searched long and often but did not find any satisfying answer to this problem).
I have a bean implementing a action-listener compatible method:
#ManagedBean(name = "myBean")
#ViewScoped
class Bean{
public String myAction(ActionEvent event){
... = event.getComponent().getAttributes().get("something");
}
}
Then, i have a jsf component like this:
<composite:interface>
<composite:attribute name="actionBean" required="true"/>
<composite:attribute name="actionMethod" method-signature="void myAction(javax.faces.event.ActionEvent)" />
</composite:interface>
<composite:implementation>
<h:form>
<p:commandButton actionListener="#{cc.attrs.actionBean[cc.attrs.actionMethod]}">
<f:attribute name="something" value="somevalue" />
</p:commandButton>
</h:form>
</composite:implementation>
It is called something like this:
<namespace:myComponent actionBean="#{myBean}" actionMethod="myAction" />
I know that this call is not working, and i wonder how to do it right!
My main intention is that i want to have a relatively generic jsf-component (would be nice to have it reusable later), that contains a button. On click to this button i want to pass an object (no simple string! in case of string i would just use action="..." and pass it via f:param). With the actionListener method i take the object via event.getComponent().getAttributes().get("something").
I think the signature void myAction(javax.faces.event.ActionEvent) is the problem that breaks passing the related method to the component, isnt it? Is it in general possible to pass method with any argument to jsf components (and if yes, how)?
So, i hope there is a possible solution to solve the general problem with altering the above strategy or maybe use something nice and different (in general i prefer not to use any hacks or workarounds, but like to use what is intended by the framework).
Thanks if somebody would find the time to point me the way! In case this question already exists, would be nice to get to the related post and have this deleted.
Try following:
<namespace:myComponent myAction="#{myBean.myAction}"/>
And composite component:
<composite:interface>
<composite:attribute name="myAction"
required="true"
method-signature="void myAction(javax.faces.event.ActionEvent)"
targetAttributeName="actionListener"/>
</composite:interface>
<composite:implementation>
<h:form>
<p:commandButton id="myAction">
<f:attribute name="something" value="somevalue" />
</p:commandButton>
</h:form>
</composite:implementation>
Check composite:attribute documentation. It has several options to pass listeners to composite component. I used targetAttributeName for this.

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