Number converter wrapping ignores locale? bug? - jsf

Is it a Bug that the first does selects between a dot or comma (always dot) according to the used f:view locale? Or is there a rule how to nest number converters.
1.
<f:converter converterId="javax.faces.BigDecimal">
<f:convertNumber maxIntegerDigits="3" maxFractionDigits="2"/>
</f:converter>
2.
<f:convertNumber maxIntegerDigits="3" maxFractionDigits="2">
<f:converter converterId="javax.faces.BigDecimal"/>
</f:convertNumber>

You cannot nest converters. They will just be applied on the closest parent UIComponent in the order as they're declared. You can also not specify multiple converters. Only the last one would really be used. Each ValueHolder component can have only one converter while each EditableValueHolder can have more than one validators.
Just stick to <f:convertNumber>. When used on input components which are already bound to a property of BigDecimal type, it'll respect the type.

Related

Type-appropriate searching in dropdowns and search boxes in frontend

I have used custom converter classes with annotations like #FacesConverter(forClass = Date.class) to override the JSF default string representation of Date and Boolean objects in the frontend. I have two problems with this:
Date works as expected – all Date objects have a consistent representation in the frontend. However, Boolean works only if I change the annotation to #FacesConverter("mypackage.presentation.BooleanFormatConverter") and then explicitly invoke it in my xhtml, each time I want to use it, as <f:converter converterId="mypackage.presentation.BooleanFormatConverter" />.
I am changing the string representation of booleans to Yes/No, and I have filter boxes on boolean columns on my datatable with those string values. However, it does not seem to recognise that the string values correspond to the boolean true/false. I don't know how to fix this without explicitly changing the type of the booleans to string in the backend, then treating those as string columns in my datatable (and for other reasons, I'd rather keep types distinct and avoid explicitly converting everything to a string in the backend).
Quite simple in the end, following Kukeltje's suggestion: a boolean in the backing bean (which does not need to be done per-column) and changing the xhtml:
<p:selectCheckboxMenu value="#{myView.yesNoCheckbox}" label="Select" onchange="PF('tableE').filter()" scrollHeight="150" filter="true" filterMatchMode="contains">
<f:selectItem itemValue="#{true}" itemLabel="Yes"/>
<f:selectItem itemValue="#{false}" itemLabel="No" />
</p:selectCheckboxMenu>
the only disadvantage is that this part must be done manually per column (my datatable has an obscene number of columns, which is why I wanted a simple global way of doing this, such as a converter).

Apply converter throughout the whole project

I would like to apply a converter to all my h:outputText in a project. Is there a way to do it for the whole project, so I don't have to repeat the tag for each field separately?
For example, assume I want the following converter.
<f:convertNumber type = "number" />
Is there a way not to repeat this for every h:outputText field that contains numeric values?
I'm afraid but this is not possible.
But you could write your own JSF outputText Component. That's pretty easy:
https://www.logicbig.com/tutorials/java-ee-tutorial/jsf/custom-component-basic.html

jsf output text with fn substring

I want to format a date in jsf which is xmlgregoriancalendar type. I've come across post which say I need custom converter. Does anybody found solution which does not require custom date converter. I was trying following but I gives me error saying...
Element type "h:outputText" must be followed by either attribute specifications, ">" or "/>".
This is what I tried on jsf
<h:outputText value="#{fn:substringBefore(aClip.lastTransmittedDate,"T")}">
<f:convertDateTime pattern="dd.MM.yyyy" />
</h:outputText>
Can anybody point out the explain the error I'm getting?
Apart from your EL syntax error (basically, with that nested double quote you're ending the attribute value too soon that it becomes value="#{fn:substringBefore(aClip.lastTransmittedDate," which is completely wrong EL syntax), this is after all absolutely not the right approach.
The <f:convertDateTime> converts Date to String and vice versa. It does not convert String in date pattern X to String in date pattern Y at all as you incorrectly seemed to expect.
Given a XMLGregorianCalendar, you need XMLGregorianCalendar#toGregorianCalendar() to get a concrete java.util.Calendar instance out of it which in turn offers a getTime() method to get a concrete java.util.Date instance out of it, ready for direct usage in <f:convertDateTime>.
Provided that your environment supports EL 2.2, this should do:
<h:outputText value="#{aClip.lastTransmittedDate.toGregorianCalendar().time}">
<f:convertDateTime pattern="dd.MM.yyyy" />
</h:outputText>
Or, if your environment doesn't support EL 2.2, then change the model in such way that you have for example a getter returning java.util.Calendar:
public Calendar getLastTransmittedDateAsCalendar() {
return lastTransmittedDate.toGregorianCalendar();
}
so that you can use
<h:outputText value="#{aClip.lastTransmittedDateAsCalendar.time}">
<f:convertDateTime pattern="dd.MM.yyyy" />
</h:outputText>
You can even add a getter returning the concrete java.util.Date.
Actually this error points that you have not well-formed XML. In EL you should use single quotes to indicate String. In your case value="#{fn:substringBefore(aClip.lastTransmittedDate,'T')}"
What about date converter, you should see on the type of #{aClip.lastTransmittedDate} property.
If it is date, just use
<h:outputText value="#{aClip.lastTransmittedDate}">
<f:convertDateTime pattern="dd.MM.yyyy" />
</h:outputText>
If it is not date (i.e. String), <f:convertDateTime/> won't work, and you should reformat it in Java code. For example, create another getter that will return modified string representing property value.

How to implement foreach in jsf?

How do I create ofer_has_location objects (join object from location and ofer) using the current ofer and the selected items from the h:selectManyCheckBox
<h:selectOneMenu id="companyidCompany"
value="#{oferController.selected.companyidCompany}"
title="#{bundle.CreateOferTitle_companyidCompany}"
required="true"
requiredMessage="#{bundle.CreateOferRequiredMessage_companyidCompany}">
<f:ajax event="valueChange" execute="companyidCompany"
render="locationCollection" />
<f:selectItems value="#{companyController.itemsAvailableSelectOne}"/>
</h:selectOneMenu>
<h:outputLabel value="#{bundle.CreateOferLabel_locationCollection}"
for="locationCollection" />
<h:selectManyListbox id="locationCollection" value="locations"
title="#{bundle.CreateOferTitle_locationCollection}">
<c:forEach items="locations">
<f:selectItems var="locations"
value="#{oferController.selected.companyidCompany.locationCollection}" />
</c:forEach>
</h:selectManyListbox>
What you need to do in order to achieve 'connected elements' functionality:
Have two elements ( <h:selectOneMenu> and <h:selectManyLisBox> in your case), where the second one will be dependent on the selected option(s) of the first one. The second element must have an id in order to be rerendered afterwards.
Every HTML select element (that's rendered by both JSF tags of your choice) will have a set of options that are not supposed to be created via iterative element like <c:forEach> (though, it is in fact possible), but rather via the <f:selectItem>/<f:selectItems> tags (thus, remove your iterative tag in comment).
When values in the components are bound not as plain Strings, or primitive wrappers (Integer, etc.), but rather as model objects (YourClass objects, etc.), then you need to tell JSF two things: how can it print option's value from your class and how can it reconstruct an object from request parameter that is a string. For this you need to implement Converter, that is, explain JSF how to do the abovementioned transformations. Use this answer and BalusC's blog as reference points. Note the appropriate syntax for <f:selectItems itemValue="..."> here.
Model values bound by these two components also need to represent your classes, just in a same way as selected items' values. For <h:selectOneMenu> it is value="#{}"; for <h:selectManyListbox> it is value="#{}" with YourClass selectOneMenuValue and List<YourClass> selectManyListboxValues or YourClass[] selectManyListboxValues bean properties respectively.
Population of second select will be handled via <f:ajax> tag. As contents need to be calculated 'on the fly', the right spot to make it is within its listener attribute (i.e. to have List<YourClass> contentsOfSecondListbox = createListboxValues(YourClass oneMenuSelectedOption);) . As you'd desire to rerender the second element, specify its client id in render attribute of <f:ajax>. Example here.
In case you are binding, for example, to String/String[] values, you won't need the converter parts.
Try to go through it step by step to find out your errors and correct them.

UIComponent#getValue() obtained via binding is not available in validator of another component

I'm trying to figure out why an f:attribute tag's value isn't passed when attached to h:inputSecret tag. I'm quite new to jsf, but as far as I know attributes can be attached to any kind of component. Here is the code:
<h:inputSecret id="passw" value="#{advertAdder.userPass}"
required="true" validator="#{advertAdder.validatePasswords}">
<f:attribute name="confirmedPass" value="#{advertAdder.passConfirmator.value}"/>
</h:inputSecret>
<h:inputSecret id="passwConfirm" required="true"
binding="#{advertAdder.passConfirmator}"/>
and the method that wants to acces this attribute:
public void validatePasswords(FacesContext context, UIComponent component, Object value)
{
if (!value.equals(component.getAttributes().get("confirmedPass")))
{
FacesMessage mess = new FacesMessage("Password and it's confirmation are not the same!");
context.addMessage(component.getClientId(context), mess);
((UIInput) component).setValid(false);
}
}
In above code component.getAttributes() always returns map with only two attributes:
javax.faces.component.VIEW_LOCATION_KEY and com.sun.faces.facelets.MARK_ID.
I've added attribute tag to a h:commandButton to check it, and then everything was fine. Am I missing something or it's not possible to add an attribute to non-action tag?
I'm using Mojarra 2.0.2 and Glassfish 3.0.1.
Thanks in advance.
Input components are processed in the order as they appear in the component tree. The UIInput#getValue() is only available when the component is already been processed. Otherwise you need to use UIInput#getSubmittedValue() instead.
<f:attribute name="confirmedPass" value="#{advertAdder.passConfirmator.submittedValue}"/>
Note that this gives you the unconverted and unvalidated value back. It would make somewhat more sense to put the validator on the confirm password field instead and pass the value of the first password field along. See also JSF Validator compare to Strings for Equality and JSF doesn't support cross-field validation, is there a workaround?
Alternatively, you can also try out the OmniFaces <o:validateEqual> component. You can find a concrete example in this article.
Unrelated to the concrete problem, it's unnecessary to bind the component to the bean this way. Replace all occurrences of #{advertAdder.passConfirmator} by #{passConfirmator}. Keep the controller free of properties which are never internally used.

Resources