Global date/boolean formatting in frontend of JSF application - jsf

I am developing a JSF dashboard web application which includes several very large PrimeFaces datatables. It would be really handy if I could set a global format for the representation of certain types – currently the only way I can think of is having backing bean methods like
public String formattedBoolean(Boolean inputBoolean) {
return inputBoolean ? "Yes" : "No";
}
which I could then manually call from the frontend (and similarly, I could use f:convertDateTime components for formatting date objects as string). However, this type of approach would require adding a lot of boilerplate XHTML, such as
<p:column headerText="Start Date" id="startDate"
sortBy="#{dataContainer.startDate}"
filterBy="#{dataContainer.startDate}">
<h:outputText value="#{dataContainer.startDate}">
<f:convertDateTime pattern="yyyy-MM-dd"/>
</h:outputText>
</p:column>
which I'd rather avoid. Does anyone know if there is a more elegant way of globally overriding the default Java string representation of objects in the frontend, or at least within the context of a data table?

Following advice above, I have decided to override the default FacesConverter for the given classes, as these are formats I'd want to present consistently in text throughout the application.

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).

create links dynamically

I have a user-defined text, such as
#SessionScoped
public class MyBean {
private String text = "Life’s but a walking shadow, a poor player
that struts and frets his hour upon the stage and
then is heard no more.";
public String getText() {
return text;
}
}
Of course the text is not static, but will be loaded from somewhere else. I want the text to be displayed one the page, as in
<h:form id="myForm">
<h:outputText value="#{myBean.text}" />
</h:form>
Now have a logic in the bean which marks certain words, e.g. every noun, in the text. These words should be rendered as links, as if they were commandLinks.
That is, the form should be submitted and I should be able to find out which link was clicked.
Something similar was already asked here, here and here, but I am not sure if the solutions given there suit my case.
My best guess right now is to split the text at the marked words into a list of snippets in the bean, e.g.
List<TextSnippet> textSnippets;
class TextSnippet {
private String precedingText;
private String markedWord;
...
}
such that each text snippet ends with a marked word. Then I would be able to iterate over the list in the xhtml, e.g.
<h:form id="myForm">
<ui:repeat var="snippet" value="#{myBean.textSnippets}">
<h:outputText value="#{snippet.precedingText}" />
<h:commandLink action="#{myBean.clickedOn(snippet.markedWord)}">
<h:outputText value="#{snippet.markedWord}">
</h:commandLink>
</ui:repeat>
</h:form>
However, I feel that this tightly couples the bean (logic of splitting) to the view. Any better ideas?
What I would personally do is try to keep the jsf tree small and implement something like the lines below that I think is more performant (disclamer: no full code coming )
Prepare the text serverside in a bean as This is a <div class="linkedWord">specific</div> word that needs a link and so is <div="linkedWord">this</div>
Output this in plain html via an <h:outputText value="#{myBean.text}"> (for escaping!)
Add a jquery dynamic eventhandler on the class="linkedWord" (so it works for each link) and call a javascript function
In that javascript function read the content of the div (or maybe add the text as a data- attribute aas well (like <div class="linkedWord" data-word="specific">specific</div>
and call a <h:commandScript> (JSF 2.3 and up) or a o:commandScript for previous JSF versions (or the `p:remoteCommand) and pass the content of the div (or the value of the attribute) as a parameter to a serverside method.
Keep in mind that there is no explicit reason to do everything in a 'JSF' way. Using client-side features and some small integration with JSF is very valid usage. People not doing this often 'blame' JSF but they themselves are effectively the cause of the less optimal behaviour)
See also:
Event binding on dynamically created elements?
http://omnifaces.org/docs/javadoc/2.6/org/omnifaces/component/script/CommandScript.html
https://javaserverfaces.github.io/docs/2.3/vdldocs/facelets/h/commandScript.html
You seem to go the right way, but I think I can suggest you some improvements. Don't know your exact requirements, but your current structure limits the marked word (which I guess acts as a mere link) to be at the end of the paragraph. What would happen if you have text after it? What about having two marked words? This class might suit better:
class TextSnippet {
private String text;
private String linkUrl;
...
}
You'll need to build the List<TextSnippet> the way you do, but evaluate the links before, so ui:repeat can access them.
Then, iterate over it. Instead of performing a POST to evaluate where to go, you've got it already, so you can use a h:link if you want to point to somewhere in your application or h:outputLink if it's outside it:
<ui:repeat var="snippet" value="#{myBean.textSnippets}">
<h:outputText value="#{snippet.text}" rendered="#{empty snippet.linkUrl}" />
<h:link outcome="#{snippet.linkUrl}" rendered="#{not empty snippet.linkUrl}">
<h:outputText value="#{snippet.text}">
</h:link>
</ui:repeat>

f:convertNumber failing when currencySymbol is obtained from bean via EL

Hi in my project I need to visualize currency value, as far in my f:convertNumber
I use a fixed currencySymbol; everything is ok, but when I try to get the symbol with an expression language like this:
<h:outputText value="#{rowItem.value}">
<f:convertNumber currencySymbol="#{rowItem.getCurrencySymbol()}" groupingUsed="true" maxFractionDigits="2" type="currency" />
</h:outputText>
it is like the method getCurrencySymbol is not called, I am sure there is something I am missing.
That will happen if #{rowItem} is only available during view render time, such as when it's specified by <h:dataTable var="rowItem">, as the variable name itself already suggests. It can also happen if #{rowItem} gets changed between building the view and rendering the view, such as when it's coming from a dropdown component in the same form. The <f:convertNumber> is namely a taghandler, not an UI component. It gets executed during view build time, not during view render time. The desired #{rowItem} value is not per definition available during view build time.
This all is explained in JSTL in JSF2 Facelets... makes sense? In that answer, you can substitute "JSTL" with <f:convertNumber> as they both are taghandlers and thus have exactly the same lifecycle.
There's no solution in standard JSF API without creating a custom converter and changing the view or model. You can find possible solutions in this answer: How to set converter properties for each row/item of h:dataTable/ui:repeat?
The JSF utility library OmniFaces offers <o:converter> out the box for exactly this problem. Use it as follows:
<h:outputText value="#{rowItem.value}">
<o:converter converterId="javax.faces.Number" currencySymbol="#{rowItem.getCurrencySymbol()}" type="currency" />
</h:outputText>
(note that I omitted the other two properties as those are the default already when type="currency" is used)

Bypass bean validation in JSF2?

I'm wondering if it's possible to bypass bean validators for certain actions in JSF2.
I've generated entities from my DB schema using NetBeans 7, which include validation attributes.
In my JSF application I have a search screen who's backing bean uses an instance of an entity to hold the user's query parameters. I then use reflection on the entity instance to generate a dynamic query to perform the user's search. Once the user performs the search they can select an item and go off to an edit page where I'd like the validation enforced.
My problem is that on the search screen, bean validation on my entity is enforced. So if my entity has 3 required fields, and the user searches on only 1 of the 3, I get two "field is required" error messages.
I know I could get around this by creating a new class for my search backing bean that doesn't have validation annotations on it, but that doesn't seem like an ideal solution to me: I'd end up with two essentially identical classes, just with different annotations.
You could add f:validateBean with disabled="true" to your first form where you don't want them validated and then not include it on the view where you do:
<h:inputText value="#{entity.property}">
<f:validateBean disabled="#{true}"/>
</h:inputText>
for me in icefaces didnt work like that: i had to :
<f:validateBean disabled="true" >
<ice:outputText value="#{messages['busqueda.bodega.tabla.datos.etiqueta.nombre']}"/> <ice:inputText" value="#busquedaBodegaBean.busquedaBodegaBB. bodegaCriterio.nombre}">
</ice:inputText>
</f:validateBean>

Best way to make an expandable/collapsible subTable with rich:dataTable

I've recently ported an application from JSF 1.1 to JSF 1.2. In the process we removed tomahawk and decided to use rich instead.
Now I need a way to make an expandable/collapsible detailViev for each row in the table.
The only thing I can think of is something along these lines (adapted from documentation at docs.jboss.com):
<rich:dataTable value="#{capitalsBean.capitals}" var="capitals">
<rich:column>
...
</rich:column>
<rich:subTable value="#{capitals.details}" var="detail" ajaxKeys="#{bean.ajaxSet}" binding="#{bean.subtable}" id="subtable" rendered="detail.detailOpened">
<rich:column>
...
</rich:column>
</rich:subTable>
</rich:dataTable>
I guess something like that would work. The problem is that I either have to add a getDetailOpened and a setDetailOpened to the objects I use, or wrap each object in another object that provides those two methods.
Anybody knows a better way, or how it is supposed to be done?
I've often added methods to my beans (or wrapper beans) which contain those properties as a way of working around JSF. It's not pretty but it works.
The only other option I can think of at the moment is to use a JavaScript function to toggle the state of the details view. That wouldn't be ideal for a number of reasons but it would save you having to keep state server-side.

Resources