execute the method before load JSF Page - spring

I am retrieving the user's locale from the database. Whenever user is login then page should display on that perticular language. So for this i am using below code in the JSF
<f:metadata>
<f:event type="preRenderView" listener="#{language.preferredLocale}"/>
</f:metadata>
<ui:define name="content_pane">
<f:view locale="#{language.localeCode}"/>
</ui:define>
//language bean code is
public void preferredLocale(ComponentSystemEvent e){
// code to retrieve locale for particular user
}
But the above code is not working to set the locale on the page onload. is there anyother way i can set the locale on the page load?

This is indeed not the right way. It's too late then. You need to make sure that <f:view locale> is already set right.
There are several ways to achieve this anyway, depending on your current application design. The simplest one would probably be the following:
#ManagedBean
#RequestScoped
public void LoginBean {
#ManagedProperty("#{localeBean}")
private LocaleBean localeBean;
public void submit() {
User user = userService.find(username, password);
if (user != null) {
localeBean.setLanguage(user.getPreferences().getLanguage());
// ...
}
// ...
}
// ...
}

use this
<f:view beforePhase=#{bean.viewBeforePhase} >

Related

Primefaces Component not updating using RequestContext

I am trying to update a primefaces component after the 'isAdmin' value changes.
I am using the following HTML page:
<h:form id="form">
<p:tabView id="tabs">
...
<p:tab title="Admin" rendered="#{userSession.isAdmin}">
...
</p:tab>
</p:tabView>
</h:form>
My UserSession class:
#ManagedBean(name="userSession")
#SessionScoped
public class UserSession {
.
.
.
public boolean isAdmin;
public UserSession() {
isAdmin = false;
}
public void addRole(String role) {
if (role.equals("ADMIN") {
this.isAdmin = true;
}
role.add(role)
}
}
The addRole() method gets called and adds the role "ADMIN". I know this isn't a good way of doing things, but I'm only using it for testing purposes at the moment.
Then, under the class where I handle login and the addRole() method gets called, I am trying to update the component using:
RequestContext.getCurrentInstance().update("form");
I have been trying to update the form as I believe this is always visible in the DOM?
My issue is, is that this is simply not working and nothing is being updated.
Any help is greatly appreciated.
I figured out that I was always actually changing my UserSession object instead of the actual session bean itself.
Therefore, I did the following and just pointed to my bean instead:
// Previously
// UserSession us = new UserSession();
UserSession us = (UserSession) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("userSession");

retaining values across screen sin JSF2.0

I am working on JSF2.0 project where I need to get value in backing bean from previous screen I have explained it below
my first screen
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
>
<h:body>
<h:form>
<h:outputText value="LocationID" />
<h:inputText value="#{getDetails.locationID}"/>
<h:commandButton value="Add OS" action="#{getDetails.addOSDetails}"/>
</h:form>
</h:body>
</html>
My backing bean when the commandButton is invoked
#ManagedBean(name="getDetails")
#RequestScoped
public class GetDetailsBean {
private String locationID;
public String getLocationID() {
return locationID;
}
public void setLocationID(String locationID) {
this.locationID = locationID;
}
public String addOSDetails(){
return "/app_pages/addOS";
}
}
My second screen which is addOS is
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
>
<h:body>
<h:form>
<h:outputText value="Enter Value" />
<h:inputText value="#{addOS.addValue}"/>
<h:commandButton value="Add OS" action="#{addOS.save}"/>
</h:form>
</h:body>
</html>
I want the LocationID entered in the first screen to be available in this backing bean
#ManagedBean(name="addOS")
#RequestScoped
public class AddOS {
private String addValue;
public String getAddValue() {
return addValue;
}
public void setAddValue(String addValue) {
this.addValue = addValue;
}
public String save(){
return "app_pages/success";
}
}
I donot want values to be set in session.Can be used.
Thoughts and help please
Thanks.
If you really intend to do a forward, as you do in your question, the submitted on the first page data is already there when the second page is rendered: remember, the forward is done within the same HTTP request. So, what you ultimately need is to keep the value for a subsequesnt POST request. You can do it, for example, by storing the information is a hidden field on the second page:
<h:inputHidden value="#{getDetails.locationID}" />
And that's basically it.
If you intend to do a redirect, thus by appending ?faces-redirect=true to a navigation case outcome, you need to store that information in EL flash to be able to retrieve it in the recepient page: there are two requests to be done. So, change your first bean's action method to the following:
public String action() {
...
FacesContext.getCurrentInstance().getExternalContext().getFlash().put("locationID", locationID);
return "result?faces-redirect=true";
}
This way on the recepient page it will be available in flash map, thus by
#{flash.locationID}
in EL scope and
(String)FacesContext.getCurrentInstance().getExternalContext()
.getFlash().get("locationID");
in Java code.

Primefaces: Editable object in accordionPanel with Dynamic = True

I am trying to achieve functionality where I am generating the tabs in according panel dynamically according to the list.
List is of say some object e.g Person
Now attribute corresponding to each person, I am showing in each tab in a form.
Values are loaded correctly but when I edit those value I am not getting updated values at the backing bean, I am getting only old values.
Can somebody please explain why ?
Here is the code.
Person Object
public class Person {
String name;
//getter setter
#Override
public String toString() {
return name;
}
}
Backing Bean
#ManagedBean(name = "editor")
public class EditorBean {
private List<Person> persons = new ArrayList<Person>();
#PostConstruct
void init() {
persons.add(new Person("dhruv"));
persons.add(new Person("tarun"));
}
public void testAction() {
System.out.println(persons);
}
// Getter Setter*****************//
public List<Person> getPersons() {
return persons;
}
public void setPersons(List<Person> persons) {
this.persons = persons;
}
}
XHTML Code:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui">
<h:head>
</h:head>
<h:body>
<h1>Hello World PrimeFaces</h1>
<h:form>
<p:accordionPanel value="#{editor.persons}" var="person" dynamic="true">
<p:tab title="#{person}">
<p:inputText value="#{person.name}"></p:inputText>
</p:tab>
</p:accordionPanel>
<p:commandButton action="#{editor.testAction()}" value="testAction"></p:commandButton>
</h:form>
</h:body>
</html>
When I run the same with with dynamic="false". This works fine. But in my real scenario I have lots of data which I cannot afford to paint in one go thats why I want to use dynamic = true.
Can somebody explain how to achieve this if not by dynamic = true ??
The reason you're having stale values in your accordion is that dynamic accordions default to cache="true". This attribute causes the accordion to not reload new/updated values. To cause an ajax refresh on tab open, set cache="false" on your accordion

Dynamic ajax navigation with <ui:include>

Suppose I want to navigate in my application, and include different facelet pages dynamically. I have a commandLink like this:
<h:commandLink value="Link" action="#{navigation.goTo('someTest')}">
<f:ajax render=":content" />
</h:commandLink>
And this is where I include the facelet:
<h:form id="content">
<ui:include src="#{navigation.includePath}" />
</h:form>
The Navigation class:
public class Navigation {
private String viewName;
public void goTo(String viewName) {
this.viewName = viewName;
}
public String getIncludePath() {
return resolvePath(viewName);
}
}
I have seen similar examples, but this doesn't work of course. As ui:include is a taghandler, the include happens long before my navigation listener is invoked. The old facelet is included, instead of the new. So far I get it.
Now to the headache part: How can I dynamically include a facelet, based on an actionListener? I tried to include the facelet in a preRender event, and a phaseListener before RENDER_RESPONSE. Both work, but in the event listener I can't include a facelet which contains an other preRender event, and in the phaseListener I get duplicate Id's after some clicks in the included facelet. However, inspecting the component tree tells me, there are no duplicate components at all. Maybe these two ideas were not to good at all..
I need a solution, where the page with the ui:include, or the Java class which includes the facelet, doesn't have to know the pages, which will be included, nor the exact path. Did anybody solve this problem before? How can I do it?
I am using JSF 2.1 and Mojarra 2.1.15
All you need to reproduce the Problem is this bean:
#Named
public class Some implements Serializable {
private static final long serialVersionUID = 1L;
private final List<String> values = new ArrayList<String>();
public Some() {
values.add("test");
}
public void setInclude(String include) {
}
public List<String> getValues() {
return values;
}
}
This in your index file:
<h:head>
<h:outputScript library="javax.faces" name="jsf.js" />
</h:head>
<h:body>
<h:form id="topform">
<h:panelGroup id="container">
<my:include src="/test.xhtml" />
</h:panelGroup>
</h:form>
</h:body>
And this in text.xhtml
<ui:repeat value="#{some.values}" var="val">
<h:commandLink value="#{val}" action="#{some.setInclude(val)}">
<f:ajax render=":topform:container" />
</h:commandLink>
</ui:repeat>
That's enough to produce an error like this:
javax.faces.FacesException: Cannot add the same component twice: topform:j_id-549384541_7e08d92c
For OmniFaces, I've also ever experimented with this by creating an <o:include> as UIComponent instead of a TagHandler which does a FaceletContext#includeFacelet() in the encodeChildren() method. This way the right included facelet is remembered during restore view phase and the included component tree only changes during render response phase, which is exactly what we want to achieve this construct.
Here's a basic kickoff example:
#FacesComponent("com.example.Include")
public class Include extends UIComponentBase {
#Override
public String getFamily() {
return "com.example.Include";
}
#Override
public boolean getRendersChildren() {
return true;
}
#Override
public void encodeChildren(FacesContext context) throws IOException {
getChildren().clear();
((FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY)).includeFacelet(this, getSrc());
super.encodeChildren(context);
}
public String getSrc() {
return (String) getStateHelper().eval("src");
}
public void setSrc(String src) {
getStateHelper().put("src", src);
}
}
Which is registered in .taglib.xml as follows:
<tag>
<tag-name>include</tag-name>
<component>
<component-type>com.example.Include</component-type>
</component>
<attribute>
<name>src</name>
<required>true</required>
<type>java.lang.String</type>
</attribute>
</tag>
This works fine with the following view:
<h:outputScript name="fixViewState.js" />
<h:form>
<ui:repeat value="#{includeBean.includes}" var="include">
<h:commandButton value="Include #{include}" action="#{includeBean.setInclude(include)}">
<f:ajax render=":include" />
</h:commandButton>
</ui:repeat>
</h:form>
<h:panelGroup id="include">
<my:include src="#{includeBean.include}.xhtml" />
</h:panelGroup>
And the following backing bean:
#ManagedBean
#ViewScoped
public class IncludeBean implements Serializable {
private List<String> includes = Arrays.asList("include1", "include2", "include3");
private String include = includes.get(0);
private List<String> getIncludes() {
return includes;
}
public void setInclude(String include) {
return this.include = include;
}
public String getInclude() {
return include;
}
}
(this example expects include files include1.xhtml, include2.xhtml and include3.xhtml in the same base folder as the main file)
The fixViewState.js can be found in this answer: h:commandButton/h:commandLink does not work on first click, works only on second click. This script is mandatory in order to fix JSF issue 790 whereby the view state get lost when there are multiple ajax forms which update each other's parent.
Also note that this way each include file can have its own <h:form> when necessary, so you don't necessarily need to put it around the include.
This approach works fine in Mojarra, even with postback requests coming from forms inside the include, however it fails hard in MyFaces with the following exception during initial request already:
java.lang.NullPointerException
at org.apache.myfaces.view.facelets.impl.FaceletCompositionContextImpl.generateUniqueId(FaceletCompositionContextImpl.java:910)
at org.apache.myfaces.view.facelets.impl.DefaultFaceletContext.generateUniqueId(DefaultFaceletContext.java:321)
at org.apache.myfaces.view.facelets.compiler.UIInstructionHandler.apply(UIInstructionHandler.java:87)
at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:49)
at org.apache.myfaces.view.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:158)
at org.apache.myfaces.view.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:57)
at org.apache.myfaces.view.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:48)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:394)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:448)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:426)
at org.apache.myfaces.view.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:244)
at com.example.Include.encodeChildren(Include.java:54)
MyFaces basically releases the Facelet context during end of view build time, making it unavailable during view render time, resulting in NPEs because the internal state has several nulled-out properties. It's however possible to add individual components instead of a Facelet file during render time. I didn't really have had the time to investigate if this is my fault or MyFaces' fault. That's also why it didn't end up in OmniFaces yet.
If you're using Mojarra anyway, feel free to use it. I however strongly recommend to test it thoroughly with all possible use cases on the very same page. Mojarra has some state saving related quirks which might fail when using this construct.

Why does the navigation only work correctly when the backing bean is session-scoped?

Consider the following page (header and stuff omitted for brevity):
<h:body>
<h:form>
<h:inputText
id="theInput"
value="#{theBean.text}">
<f:ajax render="theButton" />
</h:inputText>
<h:commandButton
id="theButton"
value="Result"
disabled="#{theBean.disabled}"
action="result" />
</h:form>
</h:body>
TheBean looks like this:
#Named
#RequestScoped
public class TheBean {
String text;
public TheBean() {
this.text = "test";
}
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
public boolean isDisabled() {
return this.text.equals("test");
}
}
result.xhtml is a placeholder that displays some static text.
The idea is to enable the button only if the entered text is valid (in this case different from the default). It works, and the button is correctly enabled if I enter something other than test, but when I click on the button, it does not navigate to result. However, it works if I do one of the following:
I make the button always enabled. This baffles me, because in the example above the button is correctly enabled, it only does not navigate to the next page. Why would that change if I leave it enabled all the time?
I change the scope of TheBean to #SessionScoped. I do not understand this either. How can the scope of the backing bean influence the page-navigation? Everything else in the example seems to work just the same with #RequestScoped.
I would really like to keep TheBean request-scoped. Is there any way to make it the navigation work without making it session-scoped?
Your bean is request scoped which means that every single HTTP request (also ajax requests!) creates a brand new bean. When you change the input, then the ajax request creates a new bean and sets the value. When you press the button, then the normal request creates a new bean (thus the value set by ajax is lost!) and determines if the button is eligible to be invoked -which is not- and thus won't invoke the action.
The view scope is designed to overcome exactly this kind of problems. Put the bean in the view scope.
#ManagedBean
#ViewScoped
public class TheBean {
This way the bean will live as long as you're interacting with the same view by either normal or ajax requests.
Sorry, I don't know how from top of head what the proper CDI declaration is. It's at least called "conversation scope".

Resources