I'm pretty new to JSF / Facelets and trying to understand where best placed to put logic when deciding whether to render content within a ui:repeat component.
In my backing bean I have a list of messages each one containing a date. I want to print all messages but only render the date when it changes.
Currently I have something like below where the backing bean getter method determines whether or not to render the message date based on logic and setting state within the backing bean.
<ui:repeat value="#{bean.orderedMessages}" var="message" varStatus="messageLoop">
<h:panelGroup rendered="#{bean.isDateRendered(messageLoop.index)}">
#{message.formattedDate}
</h:panelGroup>
// some other stuff for each message
</ui:repeat>
This is buggy and horrible since JSF calls the getter method many times before actually rendering which adds further complexity to the getter method, the code has nothing to do with the anything other than whether something should be rendered or not which should really be in the UI and the getter method has a whole bunch of nasty logic in it whereas I would prefer a simple property to be returned.
I believe the UI has to somehow store the state of the last rendered date and compare that against the one it is about to render but I'm not sure whether that's correct.
I don't believe this is an uncommon problem. Does anyone know if there is a more elegant solution to solving this?
From the thoughts raised by BalusC in the comments of the question, I have implemented the following solution.
My Message object from the entity/domain layer is returned to the backing bean when the instance is created #PostConstuct, I have created another model in the UI layer called UIAugmentedMessage which takes the Message in the constructor as well as a boolean property for isRendered and a String for the formatted date.
The backing bean builds the list of UIAugmentedMessage objects when the Message list is returned from the server just after the bean is constructed and this contains the correct state for the isRendered and formattedDate fields.
The UI layer is now simplified as follows
<ui:repeat value="#{bean.orderedMessages}" var="message">
<h:panelGroup rendered="#{message.rendered}">
#{message.formattedDate}
</h:panelGroup>
</ui:repeat>
Related
There are lot of materials out there differentiating value attribute and binding attribute in JSF.
I'm interested in how both approaches differ from each other. Given:
public class User {
private String name;
private UICommand link;
// Getters and setters omitted.
}
<h:form>
<h:commandLink binding="#{user.link}" value="#{user.name}" />
</h:form>
It is pretty straight forward what happens when a value attribute is specified. The getter runs to return the name property value of the User bean. The value is printed to HTML output.
But I couldn't understand how binding works. How does the generated HTML maintain a binding with the link property of the User bean?
Below is the relevant part of the generated output after manual beautification and commenting (note that the id j_id_jsp_1847466274_1 was auto-generated and that there are two hidden input widgets).
I'm using Sun's JSF RI, version 1.2.
<form action="/TestJSF/main.jsf" enctype="application/x-www-form-urlencoded"
id="j_id_jsp_1847466274_1" method="post" name="j_id_jsp_1847466274_1">
<input name="j_id_jsp_1847466274_1" type="hidden" value="j_id_jsp_1847466274_1">
Name
<input autocomplete="off" id="javax.faces.ViewState" name="javax.faces.ViewState"
type="hidden" value="-908991273579182886:-7278326187282654551">
</form>
Where is the binding stored here?
How does it work?
When a JSF view (Facelets/JSP file) get built/restored, a JSF component tree will be produced. At that moment, the view build time, all binding attributes are evaluated (along with id attribtues and taghandlers like JSTL). When the JSF component needs to be created before being added to the component tree, JSF will check if the binding attribute returns a precreated component (i.e. non-null) and if so, then use it. If it's not precreated, then JSF will autocreate the component "the usual way" and invoke the setter behind binding attribute with the autocreated component instance as argument.
In effects, it binds a reference of the component instance in the component tree to a scoped variable. This information is in no way visible in the generated HTML representation of the component itself. This information is in no means relevant to the generated HTML output anyway. When the form is submitted and the view is restored, the JSF component tree is just rebuilt from scratch and all binding attributes will just be re-evaluated like described in above paragraph. After the component tree is recreated, JSF will restore the JSF view state into the component tree.
Component instances are request scoped!
Important to know and understand is that the concrete component instances are effectively request scoped. They're newly created on every request and their properties are filled with values from JSF view state during restore view phase. So, if you bind the component to a property of a backing bean, then the backing bean should absolutely not be in a broader scope than the request scope. See also JSF 2.0 specitication chapter 3.1.5:
3.1.5 Component Bindings
...
Component bindings are often used in conjunction with JavaBeans that are dynamically instantiated via the Managed
Bean Creation facility (see Section 5.8.1 “VariableResolver and the Default VariableResolver”). It is strongly
recommend that application developers place managed beans that are pointed at by component binding expressions in
“request” scope. This is because placing it in session or application scope would require thread-safety, since
UIComponent instances depends on running inside of a single thread. There are also potentially negative impacts on
memory management when placing a component binding in “session” scope.
Otherwise, component instances are shared among multiple requests, possibly resulting in "duplicate component ID" errors and "weird" behaviors because validators, converters and listeners declared in the view are re-attached to the existing component instance from previous request(s). The symptoms are clear: they are executed multiple times, one time more with each request within the same scope as the component is been bound to.
And, under heavy load (i.e. when multiple different HTTP requests (threads) access and manipulate the very same component instance at the same time), you may face sooner or later an application crash with e.g. Stuck thread at UIComponent.popComponentFromEL, or Threads stuck at 100% CPU utilization in HashMap during JSF saveState(), or even some "strange" IndexOutOfBoundsException or ConcurrentModificationException coming straight from JSF implementation source code while JSF is busy saving or restoring the view state (i.e. the stack trace indicates saveState() or restoreState() methods and like).
Also, as a single component basically references the rest of the entire component tree via getParent() and getChildren(), when binding a single component to a view or session scoped bean, you're essentially saving the entire JSF component tree in the HTTP session for nothing. This will get really costly in terms of available server memory when you have relatively a lot of components in the view.
Using binding on a bean property is bad practice
Regardless, using binding this way, binding a whole component instance to a bean property, even on a request scoped bean, is in JSF 2.x a rather rare use case and generally not the best practice. It indicates a design smell. You normally declare components in the view side and bind their runtime attributes like value, and perhaps others like styleClass, disabled, rendered, etc, to normal bean properties. Then, you just manipulate exactly that bean property you want instead of grabbing the whole component and calling the setter method associated with the attribute.
In cases when a component needs to be "dynamically built" based on a static model, better is to use view build time tags like JSTL, if necessary in a tag file, instead of createComponent(), new SomeComponent(), getChildren().add() and what not. See also How to refactor snippet of old JSP to some JSF equivalent?
Or, if a component needs to be "dynamically rendered" based on a dynamic model, then just use an iterator component (<ui:repeat>, <h:dataTable>, etc). See also How to dynamically add JSF components.
Composite components is a completely different story. It's completely legit to bind components inside a <cc:implementation> to the backing component (i.e. the component identified by <cc:interface componentType>. See also a.o. Split java.util.Date over two h:inputText fields representing hour and minute with f:convertDateTime and How to implement a dynamic list with a JSF 2.0 Composite Component?
Only use binding in local scope
However, sometimes you'd like to know about the state of a different component from inside a particular component, more than often in use cases related to action/value dependent validation. For that, the binding attribute can be used, but not in combination with a bean property. You can just specify an in the local EL scope unique variable name in the binding attribute like so binding="#{foo}" and the component is during render response elsewhere in the same view directly as UIComponent reference available by #{foo}. Here are several related questions where such a solution is been used in the answer:
Validate input as required only if certain command button is pressed
How to render a component only if another component is not rendered?
JSF 2 dataTable row index without dataModel
Primefaces dependent selectOneMenu and required="true"
Validate a group of fields as required when at least one of them is filled
How to change css class for the inputfield and label when validation fails?
Getting JSF-defined component with Javascript
Use an EL expression to pass a component ID to a composite component in JSF
(and that's only from the last month...)
See also:
How to use component binding in JSF right ? (request-scoped component in session scoped bean)
View scope: java.io.NotSerializableException: javax.faces.component.html.HtmlInputText
Binding attribute causes duplicate component ID found in the view
each JSF component renders itself out to HTML and has complete control over what HTML it produces. There are many tricks that can be used by JSF, and exactly which of those tricks will be used depends on the JSF implementation you are using.
Ensure that every from input has a totaly unique name, so that when the form gets submitted back to to component tree that rendered it, it is easy to tell where each component can read its value form.
The JSF component can generate javascript that submitts back to the serer, the generated javascript knows where each component is bound too, because it was generated by the component.
For things like hlink you can include binding information in the url as query params or as part of the url itself or as matrx parameters. for examples.
http:..../somelink?componentId=123 would allow jsf to look in the component tree to see that link 123 was clicked. or it could e htp:..../jsf;LinkId=123
The easiest way to answer this question is to create a JSF page with only one link, then examine the html output it produces. That way you will know exactly how this happens using the version of JSF that you are using.
in our company we're hitting a serious problem which we think is a serious design flaw of the JSF spec, if it is the normal behavior.
This is our usecase:
SelectOneMenu (standard JSF or primefaces, doesn't matter, same behavior)
SelectItems with a database entity as it's value and a string as the label
A converter (via attribute on the selectOneMenu) which translates the entity to its ID (getAsString) and from the ID to the entity (getAsObject)
Everything works as expected as long as the entity inside the value attribute of the selectOneMenu is loaded using the same entityManager as the entities inside the selectItems. We have the same POJOs and therefore the same hashcode (Object#equals() returns true). But as soon as one of the entities is loaded via a different entityManager and therefore has a different hashcode, we are never able to get a match to generate the expected selected attribute of an select item (HTML <option /> ).
The cause of this behavior is, that the JSF-impl and primefaces both use the POJOs in the call
boolean selected = isSelected(context, menu, itemValue, valuesArray, converter);
for itemValue and valuesArray. The implementation of isSelected relies on Object#equals() for POJOs. In my opinion it should always use the value of Converter#getAsString if we have a Converter and pass it to isSelected. This is also the behavior for a POST request. Here we got a submittedValue for the selectOneMenu which is compared to the converted value of the POJO (Converter#getAsString).
Now the question:
Is this the expected behavior as it's described in the spec? Isn't the output of the converter the better way to handle this comparision? Now we have to modify our entity classes and overwrite the equals method to be able to use this construct.
Your mistake is that you forgot to implement/autogenerate equals() (and hashCode()) method conform the contract. This is beyond control of JSF. Pointing the accusing finger to JSF isn't making any sense.
It's handy to have a base entity where all your entities extend from so that you don't need to repeat the task over all entities (even though the average IDE/tool can easily autogenerate them). You can find an elaborate example in 2nd "See also" link.
See also:
Validation Error: Value is not valid
Implement converters for entities with Java Generics
I believe that this is the correct behavior. On Java side the values of the component and selection are POJOs. You have full control of the logic of their equality etc. It should not matter how it is converted to UI display and back. As a component user you should not bother to know how the POJO is displayed. As text, icon, color, whatever. The Java side of the component undestands and communicats with POJOs
YOUR CODE ----------> JAVA COMPONENT --------> CONVERTER ----------> HTML
Also I guess that relying on reference equality for entities is a road to problems. Setting equals/hashCode to use actual ID is the best approach.
The inputNumberSlider of Richfaces fails in my case to immediately update the backing bean. The setter method is never invoked. I'm right in saying, that backing bean field should should be updated on change?
<rich:inputNumberSlider
id="severityLevel"
value="#{pubController.severityLevel}"
minValue="1"
maxValue="3"
maxlength="1" />
I did set a breakpoint in the setter method, but it never rises. I must say, it works properly for all the h:inputText tags.
The setSecurityLevel setter will never be invoked till you submit the form where your rich:inputNumberSlider is contained.
Alternatively, you can set the value whenever the inputNumberSlider is changed, adding an ajax per event processing, which will execute your component (I don't use richfaces, but that would be the desired format):
<h:form>
<rich:inputNumberSlider id="severityLevel" value="#{pubController.severityLevel}"
minValue="1" maxValue="3" maxlength="1" >
<a4j:ajax event="change" execute="#this" />
</rich:inputNumberSlider>
</h:form>
Generally, that kind of behaviour is unrequired unless you want to perform some kind of validation while user is changing the input value (it also could be useful to render dependent components). In most of the cases the validation is performed over all the components once you post the whole form.
I am new bee to jsf , I am using prime faces, I did not understand how converter works, in case of single select menu.
My confusion is, is it called for converting from request parameter to object in formBean or is it called for rendering my list?
In my list If I specify
<f:selectItems
value="#{granteeSelectionManager.getGrantProgramDTOs()}"
var="grantProgramDTO" itemLabel="#{grantProgramDTO.name}"
itemValue="#{grantProgramDTO.id}" />
how to render my list and specify a converter, the converter is beign called for every item in the list?
Please help me understand if it is called for updating selection in my managed bean or for rendering or both ?
It's used for both cases.
When the list is rendered, the converter's getAsString() is used to convert the Java object behind <f:selectItem(s) itemValue> to a String which in turn is rendered as <option value> (which in turn is used as HTTP request parameter). This is indeed done on a per-item basis.
When the form is submitted, the converter's getAsObject() is used to convert the submitted value (the <option value> which appears as HTTP request parameter) back to the concrete Java object so that it can be set in the model (the backing bean) via <x:selectOneMenu value>.
In your particular case you seem to use object's own id property as item value. In such case a converter is completely unnecessary. You only need to make sure that <x:selectOneMenu value> is bound to a property of exactly the same type as <f:selectItem(s) itemValue>, which is probably Integer or Long.
If you however want to get and set a concrete Java object as value like so
<h:selectOneMenu value="#{bean.grantProgramDTO}">
<f:selectItems ... itemValue="#{grantProgramDTO}" />
</h:selectOneMenu>
then you definitely need a converter for the simple reason that Java objects can't be represented in HTML output and HTTP request parameters without converting them to their unique String representation first. In Java perspective, HTML output is basically one large String and HTTP request parameters are per definition Strings.
See also:
Our selectOneMenu wiki page
Why selectOneMenu Send ItemLabel to the converter?
Is a custom JSF converter needed for this simple class?
Conversion Error setting value for 'null Converter'
Strategy for mapping entity relationships and converting entities
How create a custom coverter in JSF 2?
I'm trying to show a 2D array as a table in a page. I know this sounds as if I was reinventing the wheel but the object I have to handle is a 2D array of a custom type that must also be rendered in a particular way (always the same).
The tricky part is that this 2D array can have null values in some of its indexes. In those cases, a particular "unavailable" cell must be rendered. The table structure (yes... <table> <tr> and <td>) was already defined by the Design Team and accepted by the client.
I've tried to use <c:forEach/> but got in trouble trying to make it work, because of the order in which JSTL and JSF tags are managed. When the JSF tags are handled there are some issues that include outdated values and missing components.
The array (attribute of a #ViewScoped bean) is always null when <c:forEach/> is invoked, even when I force the creation of the array:
public MyObject[][] getMatrix() {
if(loadedMatrix == null)
initializeMatrix();
return loadedMatrix.getTable();
}
The initializeMatrix() method obtains the corresponding data from the database and invokes the logic that creates the 2D array, making loadedMatrix reference it once it's created (all of this works, no exceptions or errors). When initializeMatrix finishes, loadedMatrix is still null.
I went for the nested <c:forEach/> option because I need to manage the indexes of the table to know what to render (if the object is null, has an availability flag set to false or if it can be rendered normally), but as for now I think the safest solution is to create a custom component.
My question is: What alternatives do I have to render the content of a 2D array as a table while being aware of the indexes I'm rendering?.
Thanks in advance
You can use ui:repeat instead of c:forEach, I tried myself with a sample and it worked for me. c:foreach is a tag-handler and please take a look at the following post of #BalusC to learn more about why you should not use tag handlers with view-scoped beans.
JSTL in JSF2 Facelets... makes sense?
<table>
<ui:repeat value="#{sampleBean.twodarray}" var="firstLevel" varStatus=#{vs}>
<tr>
<ui:repeat value="#{firstLevel}" var="secondLevel" rendered="#{!empty firstLevel}">
<td>#{vs.index} - #{secondLevel}</td>
</ui:repeat>
<h:panelGroup rendered="#{empty firstLevel}">
<td colspan="3">empty</td>
</h:panelGroup>
</tr>
</ui:repeat>
</table>