I have a JSF Page which gets few inputs from the User, I want to show a review page to the user - as what he has given as inputs in the previous page. I am using h:OutputText in the review page to show all the inputs the User had given - but when the user has reviewed and if the user wants to save them - I have a commandButton which is bound to an action method in the backing bean - which will not submit any values as the outputTexts are not submitted. What are the options do I have to show a review page at the same time get the values at the server side - I dont want to have the bean session-scoped.
I am using Apache My faces Implementation of JSF 1.2 without any component libs.
You can use h:inputHidden to retain data for the subsequent POST request. E.g.
<h:outputText value="#{bean.property}" />
<h:inputHidden value="#{bean.property}" />
When you don't have an aversion against component libraries, I'd have suggested Tomahawk's t:saveState for this. This way you don't need to specify every property separately in a hidden field.
<t:saveState value="#{bean}" />
When you're already on JSF 2.0, just putting the bean in the view scope would have been sufficient (assuming that you're conditionally rendering input form and review form in the same view). This way it lives as long as you're interacting with the same view.
#ManagedBean
#ViewScoped
public class Bean {
// ...
}
Related
I have a <p:dialog> in my general layout. I have its Header attribute hardcoded at the moment.
What I want is to access it from different beans and change its Header at run-time according to my choice.
I am using it to show a loading message to the user at the moment and want to update the loading text according to the current backend processing, e.g "waiting for server's response" etc.
<p:dialog id="main-status-dialog"
widgetVar="mainStatusDialog"
modal="true"
header="Loading..."
draggable="false"
closable="false"
resizable="false"
appendToBody="true">
Now I am calling it from different JSF pages on button clicks e.g <h:link outcome="/generalInformation" value="General Information" onclick="mainStatusDialog.show()" />
It works fine but always Show me "Loading..." because I have a hardcoaded Attribute. So how can I make it dynamic? Please note that I don't want to do it only for one page or bean, but from any page it Access it, i can Change ist Header accordingly.
Thanks!
You can use a managed property with #ManagedProperty of one of your managed beans (e.g HeaderBean)and change it every time accordingly and set the header value to this value, and it whould look dynamically updated.
#ManagedProperty("#{headerBean}")
private HeaderBean headerBean;
And in your header managed bean make a String property value where you will store the value of the header:
#ManagedBean(name = "headerBean")
#RequestScoped
public class HeaderBean implements Serializable
{
private String value = null;
// getter and setter methods
And in your p:dialog:
<p:dialog id="main-status-dialog"
widgetVar="mainStatusDialog"
modal="true"
header="#{headerBean.value}"
draggable="false"
closable="false"
resizable="false"
appendToBody="true">
Take a look at the following liks to find more about it:
The BalusC Code: Communication in JSF 2.0
Injecting Managed beans in JSF 2.0
#ManagedProperty - Inject one request scoped bean into another request scoped bean
EDIT:
You can use RequestContext to update the dialog from your beans, If you take a look at Better ajax operations and callbacks in JSF with PrimeFaces you will see that:
RequestContext API enables developers to do 2 simple things. 1st you can tell what you want to update in the xhtml based on conditions in actions that you define in your Managed Beans.To update a component from serverside, you can just write:
The code you need to update the p:dialog from your managed beans is:
RequestContext.getCurrentInstance().
addPartialUpdateTarget("header_id");
You can also use update attribute in your commandLink like this:
<h:link outcome="/generalInformation" value="General Information" oncomplete="mainStatusDialog.show()" update=":main-status-dialog"/>
I know this type of question has been asked million times here, but I couldn't find a solution for my problem in relevant posts.
JSF 1.2
I have a request-scoped bean with a method used as valueChangeListener:
class DoStuff{
...
public void step1ChkStuffIncluded_CheckedChanged(ValueChangeEvent event){
StuffDocument cd = (StuffDocument)getInfo("StuffDocument");
if(cd == null){
Logger.Error("DoStuff", "step1ChkStuffIncluded_CheckedChanged", "No stuff document (null)");
return;
}
if (step1ChkStuffIncludedChecked){
cd.handleChecked();
}
else{
cd.handleUnchecked();
}
}
...
}
by a selectBooleanCheckbox component as follows (.jspx):
...
</h:panelGroup>
<h:panelGroup rendered="#{DoStuff.pnlStep1}">
<p>
<label for="step1ChkStuffIncluded">#{DoStuff.step1ChkStuffIncludedText}</label>
<h:selectBooleanCheckbox
id="step1ChkStuffIncluded"
onchange="submit();"
value="#{DoStuff.step1ChkStuffIncludedChecked}"
valueChangeListener="#{DoStuff.step1ChkStuffIncluded_CheckedChanged}">
</h:selectBooleanCheckbox></p>
</h:panelGroup>
<div id="someDiv">
...
where
xmlns:h="http://java.sun.com/jsf/html"
Whenever the bean's scope is session, both setter and the listener for the checkbox are executed, but not in request scope. Unfortunately I can't find any clues other than that.
Any advise is greatly appreciated. Requests for further clarifications are welcome.
You've there a rendered="#{DoStuff.pnlStep1}" on a parent component. During processing of the form submit, JSF will as part of attack safeguard determine if the input component (and all of its parents) is rendered according to the server side conditions. If it's not rendered, then it will simply be skipped altogether during the processing.
That it works in a session scoped bean but fails in a request scoped bean indicates that the value behind rendered="#{DoStuff.pnlStep1}" is determined based on some request based variable/condition which was present during the request of displaying the form, but is absent during the request of processing the form submit.
To fix this, you need to make sure that you preserve exactly the same variable/condition for the value behind rendered="#{DoStuff.pnlStep1}" during the request of processing the form submit. There are several ways to achieve this, depending on the nature of the condition and how you're submitting the form. One of the ways is to pass the request based variable/condition back as a request parameter by <f:param> or <h:inputHidden>.
The canonical JSF 2.0 fix would be to put the bean in the view scope which is not available in JSF 1.2, but can be simulated using Tomahawk's <t:saveState> component.
See also:
JSF 1.2: How to keep request scoped managed bean alive across postbacks on same view?
How to call an action method of a UICommand Component which was rendered conditionally?
Primefaces 3.5.10, Mojarra 2.1.21, Omnifaces 1.5
I am thinking about security issues.
I set the component attribute with the component.getAttributes() method. This method returns a HashMap with attributes. Is it safe to set the ("disabled", true)-pair in this map to disable the component (for example p:inputText-component)? I use it from an actionListener, (Phase 5 or 4) of jsf pipeline. So possibly it has implications for render phase only. But I could manipulate the disabled attribute from input method on the client and then post the manipulated values. Does the server make test if the component is disabled and rejects the changes ?
What is the best way to go ?
all components in panelGrid will be disabled:
xhtml:
<p:panelGrid>
<my:component/>
<p:input value=#{mybean.value} />
</p:panelGrid>
Bean:
for (UIComponent component : l) {
component.getAttributes().put("disabled", true);
recursion(....);
}
But I could manipulate the disabled attribute from input method on the client and then post the manipulated values.
Yes, the enduser could.
Does the server make test if the component is disabled and rejects the changes ?
Yes, JSF does it based on component tree state, not on the submitted value. So that part is safe. It does that by the way also for readonly and rendered attribtues.
See also:
Why JSF saves the state of UI components on server?
Which properties in a JSF backing bean can be set by a user?
commandButton/commandLink/ajax action/listener method not invoked or input value not updated (point 5)
I have a view-scoped JSF-managed bean that's backing an xhtml view where I read one parameter from the URL using f:viewParam.
The view presents a form to the user. However, when the user submits the form by pressing the p:commandButton it seems that the view-scoped bean is recreated (I added a #PostConstruct annotation to verify this) and so doesn't remember the instance variable read from the f:viewParam (invId in the code below).
I originally navigate to the view with a GET that includes a URL parameter but the POST message that's send when the user presses the p:commandButton doesn't include the URL parameter. So I am thinking that when the JSF runtime doesn't see the URL parameter on the POST it considers this to be a different view and is recreating the JSF-managed bean. When I change the view scope to session-scoped the code works.
Here's the code:
view
<f:metadata>
<f:viewParam name="invId" value="#{registerBean.invId}"/>
</f:metadata>
<h:form id="registrationForm">
....
<p:commandButton value="register" action="#{registerBean.register}"
icon="ui-icon ui-icon-newwin" ajax="false"/>
</h:form>
backing bean
#ManagedBean
#ViewScoped
public class RegisterBean implements Serializable {
#ManagedProperty(value="#{invId}")
private String invId;
...
update
It turns out that this wasn't related to the URL parameters at all. Following BalusC advice below I removed the c:when tags my view was using (relying on rendered attributes instead for the same effect), and now the view-scoped bean is no longer recreated and the invId field is properly retained.
The problem is not visible in the code posted so far, but it's for JSF 2.0/2.1 a known issue that a view scoped bean will be recreated when one of its properties is been bound to an attribute of a taghandler like JSTL <c:if> or Facelets <ui:include> or a view build time attribute of JSF component, such as id and binding, while partial state saving is enabled (as by default).
The background explanation is that any EL expressions in those attributes are executed during building and restoring the view. As view scoped beans are stored in the view and thus only available after restoring the view, such an EL expression evaluation would cause a brand new and separate view scoped bean to be created. This is basically a chicken-egg issue. It's fixed in the upcoming JSF 2.2.
There are basically 3 solutions:
Change the view accordingly so that those EL expressions are only evaluated during view render time. E.g. replace <c:if>/<c:choose> by rendered.
Or bind those attributes to a request scoped bean (design notice: you can just inject a view scoped bean as a managed property of a request scoped bean).
Turn off partial state saving, if necessary only for the particular view.
See also:
JSTL in JSF2 Facelets... makes sense?
#ViewScoped fails in taghandlers
I am starting in JSF2, comming from spring mvc, so I have some doubts that I cannot find answers on Core JavaServer Faces v3
Like this one...
How can the tag h:commandButton know which bean I am talking about ? I can only have one Bean per JSF page, is that it ? I am only giving it a msg.next which is a text from a i18n file.(quizbean is my bean)
<h:body>
<h:form>
<h3>#{msgs.heading}</h3>
<p>
<h:outputFormat value="#{msgs.currentScore}">
<f:param value="#{quizBean.score}"/>
</h:outputFormat>
</p>
<p>#{msgs.guessNext}</p>
<p>#{quizBean.current.sequence}</p>
<p>
#{msgs.answer}
<h:inputText value="#{quizBean.answer}"/>
</p>
<p><h:commandButton value="#{msgs.next}"/></p>
</h:form>
The command button does not need to know this. All it generates is a HTML <input type="submit"> element. This is embedded in a HTML <form> with an action URL pointing to the same URL as the page. There's further also the <input type="hidden" name="javax.faces.ViewState">. Thanks to this field, JSF knows exactly what view you're submitting to. This view holds information about all inputs. This view knows that there's an <h:inputText value="#{quizBean.answer}" />. The view knows the field name of the generated HTML <input type="text"> element. JSF will get the submitted request parameter value by request.getParameter() using this name and then update the answer property of the current instance of quizBean with this value.
Rightclick the page in your browser and choose View Source to see the JSF-generated HTML output. Put a breakpoint on ApplyRequestValuesPhase#execute() and HtmlBasicRenderer#decode() methods (assuming that you're using Mojarra not MyFaces) to track the gathering of submitted values for every UIComponent in the view.
The bean has to be managed by JSF, then it will know which bean you are talking about.
e.g.
<f:param value="#{quizBean.score}"/>
Here, the bean quizBean is a Managed-Bean, managed by JSF.
And to make it a managed bean you to tell JSF about it by either using annotations as follows -
#ManagedBean(name="quizBean") //name is optional or you give your own name to the bean
#SessionScoped //tell JSF in which scope you want to keep your managedbean
public class QuizBean {
//....
Or by mentioning it as follows in the JSF configuration file (faces-config.xml) -
<managed-bean>
<managed-bean-name>quizBean</managed-bean-name>
<managed-bean-class>com.pkg.QuizBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
//Older versions of JSF requires this where annotations do not work
//But if you are using JSF 2.0 then it's a lot better to use annotations
You can use more than one beans in a view (page).
If this is an example from Core Java Server Faces, then read more carefully, it explains everything.
msgs as far as I remember, refers to message bundle, declared in faces-config.xml.
As for your question how commandButton knows which bean to call. In your example, the class name QuizBean, most likely correspond to the bean with the same name. That's enough for JSF 2.0. However, you could change that name by 2 methods:
1) If you use JSF managed beans, you should go like this:
#ManagedBean(name="quiz")
#ViewScoped
public class QuizBean { }
2) If you use CDI-beans you would do this:
#Named("quiz")
#RequestScoped
public class QuizBean {}
Remember that CDI-beans scope annotations come from package javax.enterprise.context. And JSF scopes are in the javax.faces.bean package. Do not mix them!
Update:
Please refer to page 35 of the book Core Java Server Faces 3rd Edition for more details about your question and do not hurry to ask questions if you don't understand something right away.