In JSF is there a way to add a passThroughAttribute to a component based on a condition or parameter? - jsf

I have an "inputSecret" component and I need to enable both HTML native non null validation, as well as JSF validation. Or to switch both of them off based on a parameter.
As a start, I have the xmlns:h="http://xmlns.jcp.org/jsf/html and xmlns:f="http://xmlns.jcp.org/jsf/core namespaces imported
This code
<h:inputSecret required="#{passwordRequired}" >
</h:inputSecret>
will enable JSF validation if the passwordRequired parameter is 'true'. And I thought the "required" attrib would also translate into the final HTML to enable native HTML validation, but it does not. So then I used the passThroughAttribute to have the "required" attribute down into the HTML rendered component.
<h:inputSecret required="#{passwordRequired}" >
<f:passThroughAttribute name="required" value="#{passwordRequired}" />
</h:inputSecret>
One problem is that the value of the passThroughAttribute does not really matter, I can set it to "required", "true", "false" or even empty string, the HTML native validation will just occur if I type in the passThroughAttribute tag as described above (again, regardless of value).
This would be fine for the use case I initially had, but there is also a situation in which the use case does not require the user to change the password, so I would like to be able to conditionally add that "required" attrib as a "passThroughAttribute" tag in the JSF code.
Something ala
<h:inputSecret required="#{passwordRequired}" >
<if:condition value="#{passwordRequired}">
<f:passThroughAttribute name="required" value="true" />
</if>
</h:inputSecret>
For an UI component I would use the "render" attribute, but this is not the case. I simply want to be able to switch the inclusion of the "passthroughAttribute" on or off based on my parameter. I know it sounds like JSTL and "c:if" but that doesn't always work so I need something else.
Does anyone know of a method for me to accomplish what I need without some horrible hacks?

Use JSTL <c:if>:
<!-- xmlns:c="http://java.sun.com/jsp/jstl/core" -->
<h:inputSecret required="#{passwordRequired}" >
<c:if test="#{passwordRequired}">
<f:passThroughAttribute name="required" value="true" />
</c:if>
</h:inputSecret>
As alternative, you could duplicate the code with a rendered condition:
<h:inputSecret required="#{passwordRequired}" rendered="#{passwordRequired}">
<f:passThroughAttribute name="required" value="#{passwordRequired}" />
</h:inputSecret>
<h:inputSecret required="#{passwordRequired}" rendered="#{!passwordRequired}"/>

Related

Not A Valid Method Expression in JSF

I have a commandbutton that I want to use to navigate to another jsf facelet, but I am getting a not a valid method expression:
<h:commandButton value="Save Edits" action="editOrDeletePage.xhtml?editing=true;#{product.id};name=#{product.productName};description=#{product.description};quantity=#{product.quantity}"/>
I can get it to work if I only have
action="editOrDeletePage.xhtml?editing=true"
I guess when I have multiple properties that I'm passing, I am not delimiting them correctly. Any ideas?
When the action attribute contains an EL expression, it's interpreted as a method expression. It's thus really only valid when you use action="#{bean.someMethod}". However, your attempt does not represent a valid method expression, it's represents instead a value expression which is not accepted by the action attribute.
If you intend to append additional request/view parameters to the form submit, then you should rather use <f:param>.
<h:commandButton value="Save Edits" action="editOrDeletePage.xhtml">
<f:param name="editing" value="true" />
<f:param name="id" value="#{product.id}" />
<f:param name="name" value="#{product.productName}" />
<f:param name="description" value="#{product.description}" />
<f:param name="quantity" value="#{product.quantity}" />
</h:commandButton>
Note that those parameters don't end up in the request URL (as you see in the browser address bar) and that your theoretical approach also wouldn't have done that, a JSF command button namely generates a HTML <input type="submit"> element which submits to the very same URL as specified in the action attribute of the parent HTML <form method="post">.
Also note that those parameters are not evaluated during the form submit, but during displaying the form. If you intented to pass submitted values along that way, then you're basically doing it wrong. Perhaps you want to specify them as view parameters so that you can use action="editOrDeletePage?faces-redirect=true&includeViewParams=true" as action.
After all, it's hard to propose the right solution for you as you didn't elaborate the concrete functional requirement in detail at all.
If you are using JSF2 you can use h:button for this
<h:button value="press here" outcome="editOrDeletePage">
<f:param name="productId" value="#{product.id}" />
</h:button>

Passing EL method expression as attribute of custom Facelets tagfile

I created a custom JSF tag:
<ui:composition>
<h:panelGroup>
<rich:dataScroller id="#{id}" for="#{table}" execute="#{table}"
page="#{scrollerPage}" render="#{table}-sc1" maxPages="5"
fastControls="hide" oncomplete="#{onCompl}" scrollListener="#{scrollListenerBean[scrollListenerMethod]}" />
<h:inputText value="#{scrollerPage}" id="#{table}-sc1" size="2">
<f:convertNumber integerOnly="true" />
</h:inputText>
<h:outputText styleClass="outputText"
value=" of #{scrollPagesCount} " />
<h:commandButton value="GO! " />
</h:panelGroup>
</ui:composition>
To pass the listener method, I used the solution suggested in a quite old blog:
<my:dataScroller id="idDS1" table="table1"
scrollerPage="#{bean.navigationHelper.scrollerPage}"
scrollPagesCount="#{bean.navigationHelper.scrollPagesCount}"
onCompl="initForm();"
scrollListenerBean="#{bean}"
scrollListenerMethod="aMethod" />
My questions are: is this the best way to do this? How can I make the method optional?
Thanks a lot for any Help! bye!
My questions are: is this the best way to do this?
That's the only way anyway, provided that you can only use standard JSF/EL facilities and you cannot create a custom taghandler.
You could however create a custom taghandler to convert the value expression to a method expression. The OmniFaces JSF utility library has a <o:methodParam> for exactly this purpose. See also the <o:methodParam> demo page.
You could then end up like:
<my:dataScroller ... scrollListener="#{bean.aMethod}" />
and
<o:methodParam name="scrollListenerMethod" value="#{scrollListener}" />
<rich:dataScroller ... scrollListener="#{scrollListenerMethod}" />
See also:
Dynamic ui include and commandButton
How can I make the method optional?
Theoretically, you could use JSTL tags to build the view conditionally. Something like:
<h:someComponent>
<c:if test="#{not empty fooAttribute}">
<f:attribute name="foo" value="#{fooAttriubte}" />
</c:if>
</h:someComponent>
But that's in the particular case of a special method expression listener attribute unfortunately not possible. There's no such thing as <rich:scrollListener> or something which allows you binding a RichFaces specific scrollListener as a separate tag to the <rich:dataScroller>. Best what you could do without creating custom taghandlers is duplicating the whole <rich:dataScroller> in two <c:if>s (or a <c:choose>); one with and other without scrollListener. This is too clumsy. You'd really better create a custom <my:richScrollListener> taghandler for this which you could then place in a <c:if>.

Custom data types in Facelets JSF 2 Expression Language

How to display a custom property using facelet expression language?
For example:
<h:outputText value="#{contact.customTypeProperty}" />
where customTypeProperty is of type CustomClass, and I want to display the String returned by its toString()?
That should already be the default behaviour. You don't need to change anything on the given code example, assuming that the toString() method is properly implemented on the CustomClass. However, if it returns HTML, you'd need to add escape="false" to the output text to prevent JSF from auto-escaping it (which it does in order to prevent XSS attacks on user-controlled input):
<h:outputText value="#{contact.customTypeProperty}" escape="false" />
This is however not necessarily the best practice. You should control the presentation in the view side, not in a toString() in the model side. For example, assuming that CustomClass has in turn two properties foo and bar and you'd like to present it in a table:
<h:panelGrid columns="2">
<h:outputText value="Foo" />
<h:outputText value="#{contact.customTypeProperty.foo}" />
<h:outputText value="Bar" />
<h:outputText value="#{contact.customTypeProperty.bar}" />
</h:panelGrid>
If you did this to avoid code repetition, then you should actually be using an include file or a tag file. See also When to use <ui:include>, tag files, composite components and/or custom components?

Check for validation errors in part of a form in JSF

I'm building a Seam application, which is basically a huge form divided into different parts, or modules. I need a way to figure out when a module is "complete", meaning all validation for the fields in that module passes. I then need to do something in the view, setting a css-class or whatever.
Something like:
<a:region id="region1">
<s:div styleClass="#{invalid ? 'errors' : ''}">
<h:inputText required="true" id="input1" />
<h:inputText required="true" id="input2" />
<h:commandButton value="Save this section" reRender="region1" />
</s:div>
</a:region>
I figured I had two options:
Using some sort of view-logic (like #{invalid} for a single field)
Using a method in the bean, where I get all components for the module programmatically, and check them for validation errors.
However, I can't find any way to do any of them. Any ideas if this is even possible?
We're using JSF 1.2 with Seam.
Thanks.
You can use UIInput#isValid() to check if a validation error has occurred on the particular input component.
<s:div styleClass="#{!input1.valid or !input2.valid ? 'errors' : ''}">
<h:inputText binding="#{input1}" required="true" id="input1" />
<h:inputText binding="#{input2}" required="true" id="input2" />
<h:commandButton value="Save this section" reRender="region1" />
</s:div>

Seam validation question - check for at least one field filled

I have a situation in my form that the user must fill at least one of the fields. Using "required" command, i cannot do that. What is the best way to validate this in seam ? i dont want to use javascript.
Thanks!
Just let the required attribute depend its outcome on the presence of the other input fields in the request parameter map.
<h:form id="form">
<h:inputText id="input1" value="#{bean.input1}" required="#{empty param['form:input2'] and empty param['form:input3']}" />
<h:inputText id="input2" value="#{bean.input2}" required="#{empty param['form:input1'] and empty param['form:input3']}" />
<h:inputText id="input3" value="#{bean.input3}" required="#{empty param['form:input1'] and empty param['form:input2']}" />
</h:form>
Alternatively you could also make use of component binding and use UIInput#getValue() to check the value of the previous components and UIInput#getSubmittedValue() to check them for the yet-to-be-validated components (components are processed in the order as they appear in the component tree). This way you don't need to hardcode client ID's. You only need to ensure that binding names doesn't conflict with existing managed bean names.
<h:form>
<h:inputText binding="#{input1}" required="#{empty input2.submittedValue and empty input3.submittedValue}" />
<h:inputText binding="#{input2}" required="#{empty input1.value and empty input3.submittedValue}" />
<h:inputText binding="#{input3}" required="#{empty input1.value and empty input2.value}" />
</h:form>
JSF2 will let you do a form-level validation. For now, you'll have to make do with either:
Validate in a Bean after form
submission and populate a
FacesMessage to the user if it fails.
Add a validator to one field and in
that validator load in the other
fields and check their values.
If you dont want to use required attribute or javascript, then there are two ways.
One of them is creating a validator, but in my opinion that is too overkill.
I would just check if the input is null or empty in your bean.
if ("".equals(theFieldYouWantToCheck) || theFieldYouWantToCheck == null) {
//Either throw exception or return "false" so that you can handle it
}
If you are using RichFaces then you could perform the validation as follows (see http://mkblog.exadel.com/ria/richfaces-ria/richfaces-built-in-client-functions/):
<h:form id="form">
<h:inputText id="input1" value="#{bean.input1}" />
<h:inputText id="input2" value="#{bean.input2}"
required="#{empty rich:findComponent('input1').submittedValue}"
requiredMessage="At least one of the fields input1 and input2 must be filled."/>
</h:form>
Note that the expression rich:findComponent('input1') is equivalent to uiComponent['input1']. The reason is that Seam provides the dynamic map uiComponent to look up UI components.

Resources