I'm writing a composite component that contains an <h:selectManyMenu> and I'd like to allow clients of this component to supply validators and converters by placing <f:validator> and <f:converter> tags as children of my composite component's tag. In my composite's interface section I have
<composite:editableValueHolder name="select-input" targets="select-many" />
and in the implementation section:
<h:selectManyMenu id="select-many" styleClass="hidden select-input" value="#{cc.attrs['value']}" binding="#{cc.inputComponent}">
<composite:insertChildren />
</h:selectManyMenu>
and finally the usage:
<cwi:selectManyMenu id="select-many-menu" value="#{selectManyBean.selectedItems}">
<f:converter converterId="converter.testItem" for="select-many" />
<f:validator validatorId="validator.testItem" for="select-input" />
<f:selectItems value="#{selectManyBean.possibleItems}" var="item" itemValue="#{item}" itemLabel="#{item.description}" />
</cwi:selectManyMenu>
The problem is neither the validator nor converter are called. I also have validator and converter classes, each annotated with #FacesValidator('validator.testItem') and #FacesConverter("converter.testItem"), respectively. They are being picked up correctly, because if I move the <f:validator> and <f:converter> tags inside the composite component, underneath <composite:insertChildren> everything works fine, but I'd rather expose these to clients than hardcode them. Is there something about the way insertChildren works when using editableValueHolder? To get this working, I could just make the converter and validator IDs part of the interface, but that loses some flexibility for passing attributes to the converters and validators.
I am using Mojarra 2.2.8-jbossorg-1. Aside from the now obvious typo, I should also have included more of my composite component's xhtml. I was using a backing component, and without the backing component, everything worked fine once I fixed the typo, but when I added the backing component, the validator and converter stopped working.
After reviewing the wiki page here for composite components https://stackoverflow.com/tags/composite-component/info I realize backing components for composite components are not the same as the classes for custom components. For composite components, they should always just extend UINamingContainer. My mistake, for specifically this selectManyMenu, was that my backing component extend UISelectMany.
Related
In one of my JSF (IceFaces 3) projects I need to implement a solution for controlling the appearance of components via XML. I managed to create something that is at least partially working: A SystemEventListener implementation is responsible for setting a component's 'disabled' and 'rendered' attributes according to the set configuration. However, these attributes can be set (with valueExpressions) in the XHTML too, in which case the component will be rendered with those values. The processing of these valueExpressions is always comes after the PreRenderComponentEvent, making my solution useless.
I'm curious: Is there any way I can ovverride or alter the valueExpressions set in the XHTML?
I have one property file linked both ways (using f:loadBundle and faces-config.xml) both with different var names. So it would look like the following:
datatypes.properties:
A=first
B=second
C=third
faces-config.xml:
<resource-bundle>
<base-name>datatypes</base-name>
<var>myProp</var>
</resource-bundle>
myPage.xhtml:
<f:loadBundle basename="datatypes" var="prop"/>
in myPage.xhtml I make a list of all the keys from the property file. What I can't seem to understand is that when I use #{prop} in the code below it works but when I replace it with #{myProp} the list no longer displays.
<h:form>
<h:selectManyListbox id="list">
<f:selectItems value="#{myProp}"></f:selectItems>
</h:selectManyListbox>
</h:form>
I figure this means the variables in both cases are not the same behind the scenes but I would appreciate it if someone could explain (or point me to an explaination) in what way they are different. I would ideally like to just use #{myProp} without having to pull the keys out in code and store them in a list.
Thanks.
Both <f:loadBundle> and <resource-bundle> are different ways to load properties with difference being in their access scopes. The latter has by the way the additional benefit that the bundle is also injectable in a managed bean by #ManagedProperty("#{myProp}")
Using <resource-bundle> in faces-config.xml creates a global resource bundle which can be accessed anywhere in your application. This is implemented through a java.util.ResourceBundle instance.
Using <f:loadBundle> in your view creates a view-specific resource bundle which is accessible only within that view. The tag handler implements this using an internal implementation of a Map. This is as specified in the VDL of the tag:
Load a resource bundle localized for the Locale of the current view,
and expose it as a java.util.Map in the request attributes of the
current request under the key specified by the value of the "var"
attribute of this tag.
Now since you're trying to use the values from datatypes.properties through <f:selectItems>, you'll get the said exception. This is because the value attribute for the tag should evaluate to a Collection or an array.
Value expression pointing at any Collection or array. The member
elements may be instances of SelectItem or any Java Object.
So in order to use the global bundle instance, you first have to convert the same into a List<SelectItem> inside your backing bean before using it.
NOTE: You can verify the above cases by setting a breakpoint in the initializeItems(Object) method in the com.sun.faces.renderkit.SelectItemsIterator class. This is, of course, assuming that you're using the Mojarra implementation.
I am using Facelets with JSF 2.0. In the facelets tag library there is a tag called <ui:component>.
It inserts an instance of UIComponent to the tree and it trims the tags outside itself.
Can anyone explain me what is the use of this kind of functionality? Why would any one want to add UIComponent instance to the tree?
I searched a lot for the examples of component tag but didn't find any.
The <ui:component> inserts a physical UIComponent instance in the component tree, with all the content as its children.
The <ui:composition> does not insert any physical UIComponent instance in the component tree, instead, it inserts all the content as children of its parent. You cannot find it via findComponent().
Composite components use implicitly <ui:component> because it basically introduces a NamingContainer component which allows reusing the same composite component multiple times in a parent without the risk to end up with duplicate component ID errors caused by the composite's children.
I followed the example here: Why does <h:inputText required="true"> allow blank spaces? to create a "Global" converter to trim all input fields. However, the converter is not being invoked when input fields are submitted.
#FacesConverter(forClass=String.class)
...
<p:inputText value="#{controller.inputValue}"/>
but when I change to:
#FacesConverter("StringTrimmer")
...
<p:inputText value="#{controller.inputValue}" converter="StringTrimmer"/>
it works.
Using Mojarra 2.1.7 and PrimeFaces 3.2
A converter with a forClass will only be invoked whenever the type of the property is an instance of the specified class. In your particular case, that can only mean that the #{controller.inputValue} is not of type String.
If you checked that the bound variable is of type String and the converter still doesn't get called, you may also check the following:
If the input component is encapsulated inside a composite component, you may have this issue. In that case, converters would not be called correctly, resulting in your custom method to be never reached. Calling the converter explicitly on the input component solves this.
If you add both value="someName" and forClass="someClass" to the #FacesConverter annotation, the forClass attribute will be ignored. This has been reported here.
This didnt work because the inputValue was not actually of type String. Once changed to type String-- it worked.
How does exactly the following code work:
#{aaa.id}
<h:inputText id="txt1" binding="#{aaa}"/>
I mean, usually the component binding works, by specifying a property (of type UIComponent) in a bean. Here, there's no bean nor property but nevertheless the name "aaa" gets bound correctly (displaying the component id - "txt1"). How does it work/where is it specified?
Thanks
UPDATE: The JSF2.0 Spec [pdf] (Chapter 3.1.5) says:
"A component binding is a special value expression that can be used to facilitate “wiring up” a component instance to a
corresponding property of a JavaBean... The specified ValueExpression must point to a read-write JavaBeans property of type UIComponent (or
appropriate subclass)."
It's been put in the default EL scope during building of the view tree (that's when all binding attributes -- and attributes of tag handlers like JSTL <c:xxx> and JSF <f:xxx> -- are being evaluated). It's being shown by normal EL means during rendering of the view tree. Rendering of the view tree happens after building of the view tree, so it works that way. It's not that this code runs "line by line" as you seemed to expect from the source.
I can't point you out a single reference where it's been specified as there is none. You'd have to read both the EL spec and JSF spec separately and do a 1+1=2.
By the way, to avoid confusion among new developers and to avoid clashes with existing variables in the EL scopes, you can use a java.util.HashMap in the request scope which is been declared as follows in faces-config.xml:
<managed-bean>
<description>Holder of all component bindings.</description>
<managed-bean-name>components</managed-bean-name>
<managed-bean-class>java.util.HashMap</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
and is been used as follows
#{components.aaa.id}
<h:inputText id="txt1" binding="#{components.aaa}"/>
which is more self-documenting.
See also:
How does the 'binding' attribute work in JSF? When and how should it be used?