is there a one-size-fits-all way to deal with popups in JSF2 (I use richfaces)?
I put together a list of requirements, I came across.
I tried a lot to overcome some of the addressed flaws, but there may exist a more complete and sophisticated example or best-practice to implement a popup in JSF.
the requirement list:
(I) the popups shall be attachted to for example a commandButton inside a dynamic list of items (a datatable or rich:tree); the item must be later be identifiable inside popup logic
(II) some logic (initialization) must be executed when popup opens
(IIIa) some logic when popup is dismissed (using a commandButton inside the popup). (IIIb) a callback action (of the calling backing bean) shall be called. (IIIc) result value should be passed to caller.
(IV) parameters need to be passed from caller to popup
(V) Can I have a (reusable) managed bean that encapsulates the popup logic? How to reference this bean from other beans? Which scope should I use?
(VI) can i avoid, that popup exists physically in DOM tree before it is shown - preventing it from being rendered/evaluated all the time
I am looking forward to your input/ideas.
regards
Related
I'm trying to implement a composite that has a few buttons in it.
This component is aimed to be used in several contexts, so the navigation cases may be passed as parameters to the component but in some cases I would like to just refresh the view (by returning null or using a void method, as mentioned in this answer) - when I use this, the view is refreshed but the component stays open (it should close on action completion) - if a navigation case is used, the page reloads (the component is effectively closed) but all selection states are lost.
Is there any way to navigate to current page without loosing state, or even just hide the composite after the actions are run?
Note: view-scope.
We are making the transition to bootstrap pages. As part of this, we are making most of our dialogs into simple include files that get rendered on demand. The include files have their own backing bean to minimize code duplication.
The typical use case is when a user enters a page a datatable shows a list of things. The user selects one or more rows in the table and then clicks a button to perform an action. The page is re-rendered using ajax. The datatable is not displayed but the former dialog is. The user then does whatever bulk operation the former dialog does and clicks execute (or cancel). The page is then re-rendered with the datatable showing and the former dialog box not.
The problem here is simple; how do you set the render flags on the datatable and former dialog box? Each of the beans needs to set the render flag of the other bean. I blithely tried injecting each bean into the other and promptly got a circular injection error at runtime. I've gone to having a callback interface that the datatable beans implement. When the former dialog bean gets injected, the datatable bean sets itself up to be called back. This works but I am not sure it's the best way to do it. Being an old swing programmer, I considered using property change listeners, which are much more robust than the simple interface, but I'm not sure what the implications of using them in a managed bean environment are. I did check out the messaging API but it clearly doesn't apply to this case.
So, what's the best way for two view beans that are backing the same page to talk to each other?
Having gone through these excellent posts:
Why JSF saves the state of UI components on server?
Why does JSF save component tree state?
and midway the JavaEE6 tutorial I still have the following questions:
When I am developing a custom UI component whose values (styleClass, value, etc) are either defined statically(in the xhtml) or set via a bean, do I need to explicitly save/restore state in the extended component as well?
Is it correct to say that the scope of the UI components is view scoped?
How is the view identified behaviour? (If I navigate away from a view, the view gets rebuild the next time around. But if I open another tab, it is restored - at least the bean!)
When I am executing an Ajax call, I would expect that 'execute' part of the UI component would be restored&processed and the 'rendered' part would be restored&updated. After running into some problems with UI:repeat, it is not clear to which extend the component tree is to be restored and if is possible to partially edit.
As an example (I am not sure that it works like this): I define a UI:repeat that iterates over some values and creates some Ajax commandlinks. Whenever I call the command, it will restore the whole ui:repeat regardless of the Ajax scope (execute/render) that I have defined. So it will re-render the whole ui:repeat. Furthermore, I don't understand how it could ever -not- restore the ui:repeat as due to being a namingcontainer it will edit the id of my newly added component.
How can I define a build-time component (vs render-time) and why would I want to do this? (It seems that build time components are troublesome when mixed with rendertime, so why have both)
Thanks
When I am developing a custom UI component whose values (styleClass, value, etc) are either defined statically(in the xhtml) or set via a bean, do I need to explicitly save/restore state in the extended component as well?
Yes. You normally use StateHelper for this.
See also:
How to save state when extending UIComponentBase
JSF custom component: support for arguments of custom types, the attribute setter is never invoked
Adding Custom Attributes to Primefaces Autocomplete Component in JSF
Is it correct to say that the scope of the UI components is view scoped?
Absolutely not. UI component instances are request scoped. Only anything which is stored via StateHelper is in essence view scoped (and restored into newly created component instances during "restore view" phase).
See also:
JSF composite component - weird behavior when trying to save state
Backing bean in composite component is recreated on every request
How is the view identified behaviour? (If I navigate away from a view, the view gets rebuild the next time around. But if I open another tab, it is restored - at least the bean!)
It's likely requested from browser cache. Try submitting a form therein. The chance is big that you get a ViewExpiredException. You need to tell the browser to not cache dynamic pages. Putting a breakpoint on bean's constructor would also confirm that it's never been invoked.
See also:
Avoid back button on JSF web application
Is JSF 2.0 View Scope back-button safe?
javax.faces.application.ViewExpiredException: View could not be restored
When I am executing an Ajax call, I would expect that 'execute' part of the UI component would be restored&processed and the 'rendered' part would be restored&updated.
This is not true as to restore part. The "whole" view state is restored. Note that the view state does since JSF 2.0 not necessarily represent the entire component tree. You've found the explanation/answer to that already in the two links mentioned in your question.
How can I define a build-time component (vs render-time) and why would I want to do this? (It seems that build time components are troublesome when mixed with rendertime, so why have both)
This is called a "tag handler". I.e. just extend from TagHandler instead of UIComponent and implement according its contract. Tag handlers are useful if the sole goal is to build the view (the JSF component tree). They do not appear in the JSF component tree. As to when to create a custom component or a custom tag handler, check the "components" and "taghandlers" sections of OmniFaces showcase, it may give some new insights as to real world use cases of those things.
See also:
Custom Facelet component in JSF
JSTL in JSF2 Facelets... makes sense?
Does anyone have a solution for such a problem:
In my app I'm using a complex, programmatically build dashboard based on the primefaces dashboard. To overcome problems with nonunique id's of the panels building the dashboard, I'm binding this component to a request-scoped bean. I'd also like to rebuild the dashboard based on some changable parameters after clicking a commandButton.
The problem is, that the getter for the dashboard is fired in the Apply Request Values phase, way before the actionListener of the commandButton is fired (in the Invoke Application phase). So, although the dashboard is rebuild eventually, it's not beeing refreshed in the rendered response.
On the other hand, if I try to set immediate attribute of the button to true, the actionListener is fired in the Apply Request Values phase, but still after the getter. Than the lifecycle goes directly to the Render Response phase, and the outcome is the same.
Anyone?
Thank you for the answer. Let me add a bit detail to my problem.
I store a model of a sports tournament as a property of a session scoped bean. It goes like this: the bean has a property "tournament". This class has a list of groups, each with it's table of matches. The idea was to use three different programmatically built components as renderers of this tournament model.
The dashboard would be used for drag-and-drop edition of contestant placement in groups. For viewing match tables and editing their matches I use a tab panel, with panel grid for every table. Finally, I use a panel grid to show a tournament tree. Every of those three components render some part of the model for the user to edit.
Since the model (and therefore those rendering components) are dynamically build depanding on chosable parameters like number of groups for example, i had a problem with id uniqnes when binding them to a session-scoped bean. So I bound them to a request scoped bean. With every request changing the model (mostly ajax) I wanted to rerender those components depending on the parameters set by the user (also stored in the session scoped bean).
The problem is, that when I rebuild the model in the invoke application phase (in a action listener fired by the "rebuild-my-model" button), the components bound to a request-scoped bean have already been "get-ed" from the bean (or so it seems), and they do not refresh on the page.
I would be very gratefull for a clue to what i'm doing wrong, and perhaps a suggestion, if the approach mentioned above is completelly stupid :)
The problem is, that the getter for the dashboard is fired in the Apply Request Values phase, way before the actionListener of the commandButton is fired
I'm not sure why exactly that forms a problem for you. Perhaps you're incorrectly doing business logic in the getter method instead of in the action listener method? Or perhaps you're manually creating the component instead of referencing the JSF-created one and thus always overridding the one in the JSF view?
A proper JSF getter method basically look like this:
public UIComponent getDashboard() {
return dashboard;
}
It should not contain any other line of code. The same applies to the setter method by the way. Any actions wherein you need to manipulate the component's children needs to be done in an action(listener) method, not in a getter/setter method.
I am trying to implement an audit trail functionality for my web application that records:
lastModified (timestamp)
modifiedBy (user information)
userComment (reason for value change)
for each of my input fields (input fields are spread over several forms with different backing beans and different valueHolder classes).
The first two (lastModified and modifiedBy) are easily done with the help of an JPA AuditListener and #PrePersit and #PreUpdate methods.
The third one is a bit tricky since it requires user interaction. Best would be a dialog that asks for the user comment.
So there are (at least) two open issues: Can I establish a "global" valueChangeListener for all input fields in my application? Is this possible without attaching <f:valueChangeListener> to each single input component? Second: How can I grab the user comment. My idea is to put a p:dialog in my web page template but this dialog needs to know from which input component it is called.
Can I establish a "global" valueChangeListener for all input fields in my application? Is this possible without attaching to each single input component?
Yes, with a SystemEventListener which get executed during PreRenderViewEvent. You need to walk through the component tree as obtained by FacesContext#getViewRoot() to find all components which are an instanceofEditableValueHolder (or something more finer-grained) and then add the new YourValueChangeListener() by the addValueChangeListener() method. See also this answer how to register the system event listener: How to apply a JSF2 phaselistener after viewroot gets built?
Second: How can I grab the user comment. My idea is to put a p:dialog in my web page template but this dialog needs to know from which input component it is called.
You could in YourValueChangeListener#processValueChange() set the component in question as a property of some request or view scoped which you grab by evaluateExpressionGet().
Recorder recorder = (Recorder) context.getApplication().evaluateExpressionGet(context, "#{recorder}", Recorder.class);
recorder.setComponent(event.getComponent());
// ...
It will execute the EL and auto-create the bean in its scope if necessary. The bean in turn should also hold the property representing the user comment. Finally, you can use it in your <p:dialog>.
<p>You have edited #{recorder.component.label}, please mention the reason:</p>
...
<h:inputText value="#{recorder.comment}" />