JSF Changing language from selectMenu doesn't invoke PostConstruct - jsf

I have in the header.xhtml change language selectOneMenu. Which by choosing changes the language properly of any xhtml file. But there are few pages where the language strings are set in the Java class itself which is invoked by the Post-Construct.
Header.xhtml
<h:selectOneMenu value="#{client.language}" onchange="submit()" >
<f:selectItems value="#{client.languages()}" />
</h:selectOneMenu>
In the managed bean, I have ViewScoped and then the PostConstruct. My problem here is- after changing the language from the menu, some string set by the Java are not translated. That's because it is invoked by the PostConstruct which is not invoked when the language is changed. But when I goto that page by clicking the link, then the strings are translated. Its just that as soon as I change language the strings aren't translated.
I think the problem here is because the PostConstruct is not invoked when the language is changed. How do I invoke it?

Your question is basically about the behavior of #PostConstruct. This method will be called once after the bean has been created and after the injection of fields has happened e.g. fields decorated with #EJB and #Resource annotations.
Since you use #ViewScoped bean, then this will be created once per view. Refreshing the page will create a new view, that's why your instance of the #ViewScoped bean will be recreated and you will process the data in the desired language.
Possible solutions:
Mark the bean that handles the view as #RequestScoped.
Use proper i18n internationalization for your output messages. Do not rely on messages being constructed from your managed bean.
In my case, I would use the latter rather than the former. Also, after changing the language, the best option is to fire a new non-ajax request-response cycle to the server.
More info:
How to choose the right bean scope?
Localization in JSF, how to remember selected locale per session instead of per request/view

I have tried to do it like you did in the past with no luck either. Here is how I work around the problem (using JQuery):
<h:selectOneMenu value="#{client.language}" onchange="$(document).find('.submitBtn').click();" >
<f:selectItems value="#{client.languages()}" />
</h:selectOneMenu>
<h:commandButton style="visibility: hidden;" styleClass="jsfHidden submitBtn" action="#{yourpostconstructmethod}"/>

Related

One <p:dialog> for multiple beans

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"/>

How to invoke a managed bean action method in on* attribute of a JSF component

I'd like to invoke a managed bean action method in an on* attribute. In my particular case I need to logout an user if the user is idle for 3 minutes as below:
<p:idleMonitor onidle="#{mybean.processTimeOut()}" timeout="180000" />
However, the managed bean action method is immediately invoked as the page loads. How is this caused and how can I solve it?
Like as all other on* attributes on all JSF components, the onidle attribute must represent a JavaScript callback, not a JSF backing bean action method. Any EL expressions in on* attributes would be evaluated immediately as String value expressions during generating the HTML output in expectation that they print (part of) JavaScript code.
It's exactly like as if you're doing <h:outputText value="#{mybean.processTimeout()}">. If you had removed the parentheses (), you'd have faced a PropertyNotFoundException which was also a hint at its own of it being evaluated as a value expression instead of a method expression.
In order to invoke a JSF backing bean method using JavaScript, you need an additional <p:remoteCommand>.
<p:idleMonitor onidle="processTimeout()" timeout="180000" />
<p:remoteCommand name="processTimeout" action="#{mybean.processTimeOut}" />
If you're not on PrimeFaces, head to the alternatives posted in this related answer: How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?

How to use component binding in JSF right ? (request-scoped component in session scoped bean)

Mojara 2.1.21
I've updated my question based on comments. I have two situation where a component is bound to server session bean. (Additional links with information: Binding attribute causes duplicate component ID found in the view and https://stackoverflow.com/a/12512672/2692917)
Version 1:
single.xhtml:
<h:outputText value=... binding="#{mysessionbean.out}" />
java:
#SessionScoped #Named public class Mysessionbean {
UIOutput out;
//getter and setter ....
}
Version 2:
template.xhtml:
<h:outputText value=... binding="#{mysessionbean.out}"
view1.xhtml:
<ui:composition template="template.xhtml" />
view2.xhtml:
<ui:composition template="template.xhtml" />
java:
#SessionScoped #Named public class Mysessionbean {
UIOutput out;
//getter and setter ....
}
Version 1 is ok. (At least I've not encounter any errors so far). But in version 2 the duplicate id error is occured if I navigate from one page to another. Why does it happen ?
Is it safe to use (request-scoped) component (in version 1) with session scoped binding ?
Are there another use cases to consider ?
Edit:
Functional requirement 1:
I want to use Primefaces datatable in a view. I need some info from this datatable. (Such as selected row or row index). So binding the datatable helps me to retrieve this info.
Functional requirement 2:
Components binding in composite components. They will be bound to session scoped bean. (And used mainly on one page, but what if I used it on another page ?
Requirements 3
The situation as in "Version 2". Template with primefaces menu and session scoped binding. For this I've used the EL-Binding.
In JSF 2.x, unless you want to manipulate components programmatically (which is at its own also rather fishy), there is no sensible real world use case to bind components to a backing bean. For sure not if they are further not been used in the backing bean itself, or if it are solely their attributes which are been flattened out.
As to the functional requirement of getting the current row of the data table, there are much better ways listed here, How can I pass selected row to commandLink inside dataTable?, for example if your environment supports EL 2.2:
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:commandLink value="Foo" action="#{bean.foo(item)}" />
The two last requirements are totally unclear. At least, if you're doing something like:
<x:someComponent binding="#{bean.someComponent}" />
with in bean
someComponent.setSomeAttribute(someAttribute);
someComponent.setOtherAttribute(otherAttribute);
then you should instead be doing
<x:someComponent someAttribute="#{bean.someAttribute}" otherAttribute="#{bean.otherAttribute}" />
Or, if you intend to be able to use the component somewhere else in the view like so
<h:inputText ... required="#{not empty param[bean.save.clientId]}" />
...
<h:commandButton binding="#{bean.save}" ... />
and the instance is further nowhere been used in the bean, then just get rid of the unnecessary property altogether:
<h:inputText ... required="#{not empty param[save.clientId]}" />
...
<h:commandButton binding="#{save}" ... />
If there is really, really no way for some unclear reason, then split all request scoped properties of the session scoped bean out into a separate request scoped bean which you in turn bind to form actions. The session scoped one can just be injected as a #ManagedProperty of the request scoped one.
See also:
Binding attribute causes duplicate component ID found in the view
How does the 'binding' attribute work in JSF? When and how should it be used?
We ran into a similar problem and I just want to share our solution:
Problem:
In a view there was a (extended largely customized) datatable.
<x:dataTable binding="#{bean.someSomeDataTable}" />
After navigating to another page and back we wanted the datatable to have the exact same state. Previously we solved that by binding the datatable to to backing bean. This worked fine with JSPs. With Facelets we could not do that (Duplicate ID errors). So we used the binding, but only saved/restored the state of the datatable component.
public HtmlDataTable getSomeDataTable()
{
HtmlDataTable htmlDataTable = new HtmlDataTable();
if (tableState != null)
htmlDataTable.restoreState(FacesContext.getCurrentInstance(), tableState);
return htmlDataTable;
}
public void setSomeDataTable(HtmlDataTable table)
{
tableState = table.saveState(FacesContext.getCurrentInstance());
}

View-scoped bean recreated on POST when URL parameters not used

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

JSF2.0, how commandButton knows which bean to send this

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.

Resources