JSF 2 - Dynamically added component's ids are not retained on postback - jsf

I have a facet within a component within which i add components dynamically using
UIComponent c = new UICustomComponent();
c.setId("someIdGeneratedDynamically");
facet.getChildren().add(c);
But on postback, when i iterate over this list, i realize that the components are present but their ids are different from the ones i specified earlier. (more specifically, these ids are of the form "j_id9, j_id10" etc)
I debugged a bit of code in StateManagementStrategyImpl and realized that they are deliberately not storing the component ids while saving the view.
My question is, why doesn't JSF store the component id?

To answer your question stated at the end: in RestoreView phase, JSF rebuilds requested view from the template file(s). It is assumed components always receive the same ids as long as the templates don't change. The state is saved using clientIds as keys. If you modified the clientId programmatically it would be impossible to restore the state properly: the recreated component would have the original id and its state would be stored under another (modified) id. That's why it doesn't "store" clientId, it's that thing that's expected to remain constant and allows matching the recreated component with its state from the previous request.
I believe this behavior applies only to components created from the templates. JSF has a dedicated mechanism to handle programmatically added components and I would expect this mechanism to deal with clientIds as expected.

Related

JSF separate DB logic from #Named bean

Good day
This question is more of a meta question than a specific problem based question.
It is always a good idea to separate any and all DB code from view related code and view files, correct?
Thus is my assumption when using JSF correct in that:
The xhtml file forms part of the view in the MVC.
The #Named backing beans also forms part of the view.
To ensure that one can relatively painlessly migrate away from JSF to another type of tech, one would ensure to not have ANY DB code inside the #Named backing beans.
All DB code should reside in a controller / service class.
The controller / service class will contain all the DB access code and business logic. This thus forms the controller of the MVC.
The #Entity classes are used to map the DB to JPA and this thus forms the model of the MVC.
Now, if my understanding of the above is correct, what would best methods and methodologies be when handling the following scenario:
I have an XHTML file displaying JSF components (Primefaces). The lists and component linked members that link the JSF components to the Java code all resides in the #Named backing bean.
Now for argument sake, let's say that the specific form is used to CRUD a supplier's information, which of the following methods is recommended as best practices (while attemping to maintain as much seperation of concern between the View and the Controller Java code) when for instance edits were made on the XHTML form:
Enforce ZERO DB code (thus never defining or using the Entity Manager) in the #Named backing bean file). The code to persist the changes after all input validation was successfully done, will reside in the Controller. To get these values to the Controller, we will have a function looking perhaps like this (basically send all the components on the xhtml form as parameters to a function in the Controller):public void supplierService (String supName, String SupAddress, String supTel....) The problem with this of course is that one may end up running into methods that takes tens of parameters. Very ugly and difficult to maintain.
Accept that separating some DB code is not possible and every #Named file must have the required JPA DB code to persist and or merge changes to the models (however if this is considered best practice, what is the use of having Controller classes?).
Create a temporary object of the same type as the model and set the attributes of this temporary object to the values obtained from the XHTML mapped components. Then only pass this temporary object to a method in the Controller. This method in the Controller will then persist and or merge the passed object's info. However I feel this may introduce unnecessary object instantiation overhead. Also I am not 100% sure what exactly happens 'behind the scenes' when I have a model named SupplierEntity.java that is mapped via JPA to a PostgreSQL DB and I call this code: SupplierEntity tempSup = new SupplierEntity(); Will JPA via Hibernate on Wildfly actually at this point create a new entity (record in the DB), and as such I cannot use this to create a temporary object to hold the values I am passing to the Controller as a temp instance of the underlying JPA entity, or will Hibernate (using JPA 2.1) ONLY create a new record when I do em.persist(mySupplier); and thus it is safe to use this method to pass objects to the controller's persisting method, instead of passing tens of parameters to the persisting method.
Something completely different than what I mentioned above is considered to be the best practice for separating the MVC components in JSF as much as possible, while still preventing having to pass 50 parameters to the Controller.
Please as said right in the start, this is a meta question regarding best practices. If Stackoverflow is not the right forum for these questions, instead of down voting this into oblivion, please let me know where I should ask instead and I will gladly delete the question from here and create it on the right forum.

Storing properties of a custom component in session scope or bean

I've written a new back-end Java component (extending UIComponentBase) as an alternative for the ExtLib Application Layout control. The control needs to show a collection of data that is looked up from another Notes application. The data is user dependant and doesn't change from page to page so, to avoid repeatedly doing a lookup to the other application, I want to store it in the session scope. (Note that because this is a layout control, there will only ever be one per page.)
I know I could use a session-scoped maanged bean (and have done in previous iterations) but the data only needs to be used in this control and shouldn't be used elsewhere on the page which it could be with a bean. So my question is, what's the best practice approach I should take here? Should I just directly store the data in the sessionMap or am I missing a trick with the component stateHolder? Or am I stuck with using a bean?
Thanks
(Edited for clarification)
It looks like you're talking about your own back-end Java components rather than Custom Controls within a single NSF.
I'm not sure at what level, when you write your own native XPages components, the properties are cached by the stateHolder when calling saveState(). I would presume no higher than View, for the reasons Frantisek says, that otherwise it would be unclear which instance to update if you had multiple on one XPage but one on another. It couldn't update both at the same time on the same page, so I would guess that each is a separate instance. As a result, the same component on multiple pages would be a separate discreet instance.
But there's nothing stopping you, in specific setters of the component, writing to sessionScope as well as the private property, and then doing the reverse on the getter. I'm not sure if you'd want to try the internal property before trying sessionScope or vice versa. It would depend how you wanted to handle the situation of the same sessionScope being updated from multiple pages (if the collection could change).

Persisting ViewScoped beans across multiple views

Ok I know scope questions come up all the time but I'm interested in a slightly different approach to the solution. The #ViewScope is a fantastic bridge between the #RequestScope and the #SessionScope.
However there is still a common use case (at least for me) where I really don't want to use #SessionScope but I need the data over a couple of views. A really simple case is when I have multiple datatables chained together each one depending on previous selections.
It's perfectly possible to use <f:paramView> and pass a single or even a couple of pieces of data as params in the address and then retrieve everything from the database again. I am more interested in finding a way of creating a 'snapshot' of the beans state / variables, creating the new #ViewScope and then 'restoring' the 'snapshot state' to the new bean.
Does such a thing exist? Ideas? Opinions?
I don't know if this is the 'accepted solution' but I've implemented an idea that works for me. (Feedback appreciated!)
So I have created a #SessionScoped class with a couple of static maps:
private static Map<String, Object> objectVariableMap;
// Getters, setters and methods etc. are omitted for simplicity
The idea being that I have specified a map that accepts a String as the key and an Object as the value. I've specifically not set the type of object to allow me to store any type of object in there. The caveat is that you need to be sure of the type of object when retrieving it so you can cast it back into its original type.
Now comes the time to set the data from the first #ViewScoped. I generate a random UUID (or what ever you want) as the Map key and then set the value to the object I'm working with (ie. this, or indeed any other objects you might want to pass to the next view). Save the key, value into the map and set the URL param to the key.
I'm never keen on passing data like user id's etc. in URL params (even when its encrypted). This idea has the added benefit of offering disposable URL values that have a specifiable life span.
On the receiving end (ie. The new #ViewScoped bean, or any other scope for that matter) you read in the URL param (the map key) using <f:paramView> and then use a preRenderView event to retrieve and set the Object where working with.
At this point you can choose to remove the key pair from the Map and invalidate the ability to retrieve that object or you can keep keep the key pair for a longer duration by simply updating the object if there are any changes.
UPDATE: Conceptually this has been really successful (for me at least). I've created a handfull of useful methods and classes surrounding the concept to make it more universal. If anybody wants more specific instructions or I might even create a small library if anybody wants.
You can use the CDI "Conversation Scope" for this. This is narrower than the session scope but wider than the view scope.
If the pages between which you pass parameters are a unit, you can also make them a flow in JSF 2.2 and use the flow scope.
Projects like CODI offer various other scopes that can be used between pages.

Data flow between views in JSF 2

I'm currently building my first JSF 2 application and I have some questions regarding flow of data between views.
Background
The application keeps track of competences of IT-consultants. To illustrate my questions, I will just describe a small part of it. A Competence entity has a many-to-one relation to a Area entity, putting the different competences in groups. I have views to handle these: Competence.xhtml, EditCompetence.xhtml and EditCompetenceArea.xhtml. These are backed up by a ManagedBean, AdminCompetenceController.
Competence.xhtml lists all Areas in a table, and lists all Competences in an Area if the user clicks on its row. It also has a new-button for Competences and Areas, and an Edit-button for each Competence and Area. these leads to EditCompetence.xhtml and EditCompetenceArea.xhtml respectivly, where the user can fill in information about a Competence or and Area.
Questions
What is the recommended way to handle flow of information between these pages? For example: EditCompetenceArea.xhtml needs to know which Area it should edit (or if it should make a new one). Should I have one backing bean per view or one for all of them? Should it be Session scoped and keep track of the selected Area/Competence with variables? Or should it be View scoped and send the id of the selected object with viewParams? Is it even possible to use Request scope? I've tried several of these and have run into practical problems with each method.
Is it possible to use viewParam to transfer information between views using different backing beans?
Is it possible to use viewParam with a Request scoped backing bean? The data seems to disappear from the bean before I can use it in the postback.
Also, if anyone can recommend any reading material (preferably free, online) regarding more general design patterns rather than specific smaller problems in JSF 2, I would really appreciate it.
To retain data in conversations with the same view, put the bean in view scope. The data will get lost after you navigate to a different view.
To retain data in conversations with different views, either put the bean in session scope to keep it alive among all requests/views, or use <h:inputHidden>, <f:setPropertyActionListener>, etc to retain request scoped data in subsequent request.
In your particular case, I'd go with single main #ViewScoped bean and a single CRUD view wherein the display table and the edit form is included/rendered conditionally.

JSF how to temporary disable validators to save draft

I have a pretty complex form with lots of inputs and validators. For the user it takes pretty long time (even over an hour) to complete that, so they would like to be able to save the draft data, even if it violates rules like mandatory fields being not typed in.
I believe this problem is common to many web applications, but can't find any well recognised pattern how this should be implemented. Can you please advise how to achieve that?
For now I can see the following options:
use of immediate=true on "Save draft" button doesn't work, as the UI data would not be stored on the bean, so I wouldn't be able to access it. Technically I could find the data in UI component tree, but traversing that doesn't seem to be a good idea.
remove all the fields validation from the page and validate the data programmaticaly in the action listener defined for the form. Again, not a good idea, form is really complex, there are plenty of fields so validation implemented this way would be very messy.
implement my own validators, that would be controlled by some request attribute, which would be set for standard form submission (with full validation expected) and would be unset for "save as draft" submission (when validation should be skipped). Again, not a good solution, I would need to provide my own wrappers for all validators I am using.
But as you see no one is really reasonable. Is there really no simple solution to the problem?
It's indeed not that easy. Validation is pretty tight coupled in JSF lifecycle.
I would personally go for option 1. True, dirty work, but you can just hide that away in an utility class or so. Just grab the <h:form> in question from the viewroot, iterate over its children recursively, hereby testing if component instanceof EditableValueHolder is true, store the found id-value pair in sort of Map and finally persist it.
As a fourth alternative, you could save all the data independently using ajaxical powers. jQuery is helpful in this.
$.post('/savedraft', $('#formid').serialize());
It only requires Javascript support at the client side.
Update: the JSF utility library OmniFaces has a <o:ignoreValidationFailed> taghandler for the exact purpose. It was indeed not a simple solution as it requires a custom <h:form> as well. It does its job by providing a custom FacesContext instance during the validations and update model values phases which does a NOOP in the validationFailed() and renderResponse() methods. So the components are still invalidated and the messages are still attached, but it would still proceed to the update model values and invoke application phases.
I had the same problem and I didn't like the idea of skipping all the validations. After a lot of thought I ended up wanting only to skip required fields validation. The logic behind this is the user either complete a field correctly or doesn't complete it at all. This is very important for me because everything ends up in the database and, of course, I don't want to overflow a database field or end up saving a String value into an INT database field for instance.
In my experience, skipping required fields allows enough margin of manoeuvre to save a draft. To achieve that I ended up writing a requiredWarnValidator that shows up a single warn message.
public void validate(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
if (value == null) {
FacesMessage message = new FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_WARN);
message.setSummary("This field is required.");
context.addMessage(component.getClientId(), message);
context.validationFailed();
}
}
In this validator I do not throw a ValidatorException() because I want to pass the validation phase but I call validationFailed() because I want to know if a required field is not filled.
I have a flag (completed) in the entity I use to save my form. When saving the form, I check isValidationFailed().
if true at least one required field is not filled : I uncheck the flag completed. (it is a draft)
if false all the form is completed : I check the flag completed. (it is not a draft)
This also allows me to have a single "Save" button instead of two buttons ("Save" and "Save as a draft").
Notes and known pitfalls :
If you are saving your draft to the database then you have to make sure there are no NOT NULL constraints.
When using converters and validators you have to make sure they can handle NULL values.
You will lose the required field asterisk in the outputLabel for your fields.

Resources