Enum values in Composite Component attribute - attributes

My issue is quite simple : I want to create a composite component with a String attribute, Type.
<cc:attribute name="type" />
This attribute will have 3 acceptable values, [TYPE1, TYPE2, TYPE3]
Is it possible to say my component will accept only these values ?

Unfortunately no, you cannot put a compile/buildtime restriction on a composite component attribute value in the cc interface. You can however put a runtime restriction by checking the value in the cc implementation.
<ui:param name="type" value="#{cc.attrs.type}" />
<ui:fragment rendered="#{type == 'TYPE1' or type == 'TYPE2' or type == 'TYPE3'}">
<p>The type is TYPE1, TYPE2 or TYPE3.</p>
<p>Write your component's body here.</p>
</ui:fragment>
That'll be your best bet.

Related

How to use composite component attrs in targets

I have this piece of code:
<composite:interface componentType="nestedGridCellEditor">
<composite:attribute name="componentName" required="false" shortDescription="Name of the attribute to display in the id"/>
<composite:attribute name="action" required="false" targets="#{cc.attrs.componentName}button" shortDescription="A method expression or a string outcome to process when command is executed"/>
</composite:interface>
<composite:implementation>
<span id="#{cc.clientId}" style="display: flex;">
<p:commandButton id="#{cc.attrs.componentName}button"/>
</composite:implementation>
</span>
And I use it that way (I'm using it several of times, with a different componentName):
<sm:nestedGridCellEditor id="DateNGCE" componentName="Foo2101"
action="#{contractTermsBudgetController.updateRow('Date', budget)}"/>
What I want it to do is to use componentName inside the id of the component, and to put it inside the targets as well.
Right now it giving me an error about the targets and about the action method.
(i.e - "Unable to re-target MethodExpression as inner component referenced by target id 'button' cannot be found")
How can I do this?
EDIT
The purpose of this is because I'm using this composite inside several tables and I want to identify each button by its table's ID which should include the table name and not the clientId.
That's why I need to pass the name through the componentName.

JSF composite:attribute with f:attribute conversion error

I'm implementing a JSF component and need to conditionally add some attributes. This question is similar to a previous JSF: p:dataTable with f:attribute results in "argument type mismatch" error, but with a completely different error message, so I raised a new question.
<composite:interface>
<composite:attribute name="filter" required="false" default="false"
type="java.lang.Boolean"/>
<composite:attribute name="rows" required="false" default="15"
type="java.lang.Integer"/>
...
</composite:interface>
<composite:implementation>
<p:dataTable ivar="p" value="#{cc.attrs.dm}">
<c:if test="#{cc.attrs.filter}">
<f:attribute name="paginator" value="#{true}"/>
<f:attribute name="rows" value="#{cc.attrs.rows}"/>
</c:if>
...
<p:dataTable>
</composite:implementation>
This results in an error java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer. Even if I manually set this, I get errors:
<f:attribute name="rows" value="15"/> ... argument type mismatch
<f:attribute name="rows" value="#{15}"/> ... java.lang.Long cannot be cast
to java.lang.Integer
If I add the attribute directly, there is no exception and the correct number of rows is diplayed:
<p:dataTable var="p" value="#{cc.attrs.dm}" rows="#{cc.attrs.rows}">
This is indeed an unfortunate corner case with numbers in EL and composite component attributes. There's no solution for this. The type information is not available in #{cc.attrs} when used in <f:attribute> and thus treated as String. The #{15} cannot be represented as an integer in EL either, all numbers are always implicitly treated as Long when the type information is absent. The ClassCastException can be prevented by using a tag file instead of a composite component.
Your best bet is doing the check in the actual rows attribute itself.
<p:dataTable ... rows="#{cc.attrs.filter ? cc.attrs.rows : null}">

JSF Number Validation

Is there any inbuilt number validator tag in JSF that checks whether an input entered in h:inputext field is a number?
The first question was answered. Edited to explain the next problem:
<h:inputText id="maxrecs" value="#{simpleBean.numRecords}" required="false" maxlength="4" >
<f:convertNumber longOnly="true"/>
</h:inputText>
Backing Bean
private long numRecords = null;
If I use String or Integer object in the backing bean , value is not being set. Now when I use primitive int, 0 is being printed on the screen. I would like the screen to be empty.
You can use f:convertNumber (use the integerOnly attribute).
You can get more information here.
You can use:
<f:validateLongRange minimum="20" maximum="1000" />
Where minimum is the smallest number allowed and maximum is the largest.
Look here for more details
JSF Number validation for inputtext
mention f:converterNumber component in between h inputText component and mention the attributes integerOnly and type.
<h:inputText id="textMobileId" label="Mobile" styleClass="controlfont" value="#{UserRegistrationBean.textMobile}">
<f:convertNumber integerOnly="true" type="number" />
</h:inputText>
If you enter abcd in Mobile textbox at the time when you click on commandbutton it automatically shows an error like
Mobile: 'abcd' is not a number.
i8taken solution converts number into long without validation message (at least in my case: JSF2 / global messages per page). For proper validation message you can
1. check value in action method in bean;
or
2. use converter attribute for inputText:
<h:inputText id="maxrecs" value="#{simpleBean.numRecords}" maxlength="4" converter="javax.faces.Integer" />
You can simply use the passthrough, so first add this library
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
and after use this
<h:inputText id="numberId" pt:type="number" />

Concatenation of property name (EL) in JSF

How can I concatenate the name of a property using the EL?
This is what I tried:
<ui:repeat value="#{someBean.getParts()}" var="part">
<h:inputTextarea value="#{someOtherBean.result}#{part}" />
</ui:repeat>
But it didn't work.
The bean has the four property resultA, resultB, resultC and resultD. getParts() returns "A", "B", "C", and "D".
It's quite possible though. You can use <ui:param> to prepare the dynamic property name and use the brace notation [] to access it.
<ui:repeat value="#{someBean.parts}" var="part">
<ui:param name="resultPart" value="result#{part}" />
<h:inputTextarea value="#{someOtherBean[resultPart]}" />
</ui:repeat>
Needless to say that I agree with Michael that this is a smell in the model design.
I don't think that can be made to work without changing the design. It's generally a bad idea in Java to have a design that requires you to access methods fields and properties through a name, and worse if the name is built from strings.
Possible solutions:
have getParts() return "resultA", "resultB", etc. and access them #{someOtherBean[getParts()]}
change the property names to a, b, c, d and access them as #{someOtherBean[getParts()]}
have a single property result that contains a Map with "A", "B", etc as keys and access the values as #{someOtherBean.result[getParts()]}

JSF: Ternary operator used to assign a value to an <f:param> fails

I am using JSF tags within an XHTML file. My intention is to enable or disable a <rich:MenuItem> context-menu item by setting the "disabled" attribute to "true" or "false" appropriately. To do this, I am using a backing bean variable in a ternary operator and setting an <f:param> value to either "true" or "false" based on the bean variable, as below:
<rich:componentControl event="oncontextmenu" for="network-tree-menu"
operation="show">
<f:param id="nestlevel" value="#{item.nestLevel > 10 ? 'true' : 'false'}"
name="nestlevel" />
</rich:componentControl>
where item is the backing bean and item.nestLevel is an integer.
I am using this <f:param> value later in the XHTML file as below:
<rich:contextMenu ...
<rich:menuItem id="abc" ajaxSingle="true" disabled="{nestlevel}"
onclick="doSomething();" value="Do something...">
</rich:contextMenu>
This is not working !! The menu item is always enabled, (I guess this is the default behaviour) even though the result of the ternary operation is "true". Is there something I am missing here w.r.t the syntax, or is there some other way I can do this conditional enabling of context-menu items within the XHTML file?
Thanks in advance.
Regards,
Nagendra U M
How about this:
<f:param id="nestlevel" value="#{item.nestLevel > 10}" name="nestlevel" />

Resources