A quite simple and straight-forward question.
I have a session scoped managed bean as follows (demonstrating a PrimeFaces range slider).
#ManagedBean
#SessionScoped
public final class RangeSliderBean implements Serializable
{
private static final long serialVersionUID = 1L;
private static final byte scale=2;
private BigDecimal maxPrice;
private BigDecimal minPrice;
public RangeSliderBean()
{
maxPrice=new BigDecimal(100).setScale(scale, RoundingMode.HALF_UP);
minPrice=new BigDecimal(5).setScale(scale, RoundingMode.HALF_UP);
}
#PostConstruct
private void init()
{
}
//Mutators and accessors
}
The given two fields in the above session scoped managed bean are bound to an XHTML page.
<h:form id="rangeForm" prependId="true">
<p:panel header="Shop by Price">
<h:panelGrid id="rangeSliderPanelGrid" columns="1" style="margin-bottom:10px">
<h:outputText id="displayRange" value="Min : #{rangeSliderBean.minPrice.toPlainString()} Max : #{rangeSliderBean.maxPrice.toPlainString()}"/>
<p:slider for="txtMinPrice, txtMaxPrice"
minValue="#{rangeSliderBean.minPrice}"
maxValue="#{rangeSliderBean.maxPrice}"
display="displayRange"
style="width:170px"
range="true" displayTemplate="Min : {min} Max : {max}"/>
</h:panelGrid>
<h:inputHidden id="txtMinPrice" value="#{rangeSliderBean.minPrice}" converter="#{bigDecimalConverter}"/>
<h:inputHidden id="txtMaxPrice" value="#{rangeSliderBean.maxPrice}" converter="#{bigDecimalConverter}"/>
<p:commandButton value="Submit"/> <!--Update/process is temporarily omitted.-->
</p:panel>
</h:form>
If these fields are initialized in the method annotated by #PostConstruct i.e init(), in this case (instead of initializing them in the constructor as shown in the snippet), their specified values are not set unless and until a user logs in (unless a session is created).
How can they be initialized in the constructor then, just a little confusion? (I know that the constructor is called before the method annotated by #PostConstruct is invoked).
How can they be initialized in the constructor then, just a little
confusion? (I know that the constructor is called before the method
annotated by #PostConstruct is invoked).
Use the #PostConstruct's init method only to initialize fields which are being injected (i.e Ejbs). If you don't have any injections and dependencies, init method becomes pretty useless. The bean's constructor is used to initialize bean's own properties. In your example, you don't have any injection, so you can safely remove that #PostConstruct's init method.
If these fields are initialized in the method annotated by
#PostConstruct i.e init(), in this case (instead of initializing them
in the constructor as shown in the snippet), their specified values
are not set unless and until a user logs in (unless a session is
created).
It's the normal behavior, there is no reason to emphasize on the not, because a #SessionScoped bean is created and initialized only when a new session is created.
For more info check the link, the question has already been answered : Why use #PostConstruct?
Related
I try to add a object to a LinkedList in a #ConversationScoped backing bean.
#Named
#ConversationScoped
public class CategoryController implements Serializable{
...
private List<Category> selectedCategories = new LinkedList<Category>();
...
#PostConstruct
public void initNewMember() {
conversation.begin();
newCategory = new Category();
loadExistingCategories();
}
...
}
I want to send an ajax request with new objects (of type category). They should simply be added to the linked list.
this.selectedCategories.add(newParentCategory);
With the ajax render attribute <f:ajax render="allSelectedCategories"/> I immediately render the output text to render the object list.
<h:outputText id="allSelectedCategories" value="#{categoryController.selectedCategories}" />
And yes, the object I clicked is displayed, but the previously clicked objects are gone.
The values do not serialize/persist in memory during my "conversation". What do I need to do to make that conversion scope temporarily persist the values of the ajax calls?
I really want to get used to CDI and abandon the ManagedBean path for this project (e.g. #ViewScoped), despite the fact that it works like a charm.
Also, I cannot reproduce the following tutorial on CDI Conversation Scope. I simply cannot debug into the initConversation by adding
<f:event listener="#{categoryController.initConversation}"
type="preRenderView"></f:event>
Is it possible to invoke more than one listener method using a single command component? For example,
A view scoped bean:
#ManagedBean
#ViewScoped
public final class ViewScopedBean implements Serializable
{
#ManagedProperty(value = "#{sessionScopedBean}")
private SessionScopedBean sessionScopedBean; //Getter/Setter.
private static final long serialVersionUID = 1L;
public ViewScopedBean() {}
public void action()
{
//Do something.
sessionScopedBean.action();
}
}
A session scoped bean:
#ManagedBean
#SessionScoped
public final class SessionScopedBean implements Serializable
{
private static final long serialVersionUID = 1L;
public SessionScopedBean () {}
public void action() {
//Do something.
}
}
A command button like the one given below,
<h:commandButton value="Action" actionListener="#{viewScopedBean.action}"/>
invokes the method action() in ViewScopedBean which in turn invokes the action() method in SessionScopedBean by injecting an instance of that bean.
Is it somehow possible do the same on XHTML so that a need to inject a bean just to invoke a method can be eliminated?
Use <f:actionListener binding>:
<h:commandButton value="Action">
<f:actionListener binding="#{viewScopedBean.action()}"/>
<f:actionListener binding="#{sessionScopedBean.action()}"/>
</h:commandButton />
Note the importance of the parentheses in EL. Omitting them would in this particular example otherwise throw a confusing javax.el.PropertyNotFoundException: Property 'action' not found on type com.example.ViewScopedBean, because it's by default interpreted as a value expression. Adding parentheses makes it a method expression. See also Why am I able to bind <f:actionListener> to an arbitrary method if it's not supported by JSF?
You could even add an actionListener and/or an action method to the component the usual way, which is invoked later on. What it has to be unique is the action method, which decides the outcome for the processing.
Anyway, keep in mind the listeners are always executed before the action and considered a "warming-up" for it. Your best is to perform the whole logic in the action method, even if you need to do bean injections.
See also:
Call multiple backing bean methods at the same time
Differences between action and actionListener
i'm using jsf + primefaces 3.5. And my button isn't calling one method in my managed bean.
I have this xhtml:
<h:form>
<p:inputText id="name" value="#{userMB.userSelected.name}" />
<p:commandButton id="btnSave" value="Salvar" actionListener="#{userMB.save}"/>
</h:form>
And my managed bean is:
#ManagedBean
#SessionScoped
public class UsuarioMB implements Serializable{
User userSelected;
public void save(){
System.out.println(userSelected.getName());
//call my daos and persist in database
}
}
The most curious is that if i remove the , the method is called!
If i put a atribute in p:commandButton "imediate = true ", the method is called, BUT, the information (userSelected.name) is null !
Thanks very much :)
It failed because it threw a NullPointerException because you never initialized userSelected.
Add this to your bean:
#PostConstruct
public void init() {
userSelected = new User();
}
If you have paid attention to the server logs, you should have seen it. As to the complete absence of feedback about the exception in the webbrowser, whereas in normal synchronous (non-ajax) you would have seen a HTTP 500 error page, it's because you're sending an ajax request without apparently an ExceptionHandler configured.
That it works when you set immediate="true" on the button is simply because it will then bypass the processing of all input components which do not have immediate="true" set.
See also:
What is the correct way to deal with JSF 2.0 exceptions for AJAXified components?
You have not given a name to the managedbean UsuarioMB. As suche it will be named usuarioMB.
#ManagedBean – marks this bean to be a managed bean with the name
specified in name attribute. If the name attribute in #ManagedBean is
not specified, then the managed bean name will default to class name
portion of the fully qualified class name.
read more about it in this blog: http://mkblog.exadel.com/2009/08/learning-jsf2-managed-beans/
Secondly, if your code above is complete, you are lacking public getter and setter for userSelected.
Thirdly you are missing the ActionEvent as you have declared a parameterless actionlistener, see Differences between action and actionListener
In order to get you code working you will need to change your xhtml to
<h:form>
<p:inputText id="name" value="#{usuarioMB.userSelected.name}" />
<p:commandButton id="btnSave" value="Salvar" actionListener="#{usuarioMB.save}"/>
</h:form>
And your managed bean as follows
import javax.faces.event.ActionEvent;
// ...
#ManagedBean
#SessionScoped
public class UsuarioMB implements Serializable{
private User userSelected;
public void save(ActionEvent event){
System.out.println(userSelected.getName());
}
public User getUserSelected() {
return userSelected;
}
public void setUserSelected(User userSelected) {
this.userSelected = userSelected;
}
}
This question already has answers here:
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)
(3 answers)
Closed 1 year ago.
I'm relatively new to JSF and trying to learn how current JSF 2 applications are designed. I've seen reference to single page applications that use ajax. Can someone fill me in on some of the techniques used and / or point me to a model or book? The books I've seen (JSF Complete Reference etc.) are good for basic tech issues but I can't find a source for current design techniques.
Thanks
Dave
In order to implement your Single Page Application, you should state which piece of your page should be rendered. This can be accomplished making use of a boolean flag such as create, edit, list, and so on. For instance, see the following (Just relevant code)
<h:body>
<h:form rendered="#{userController.stateManager.create}">
<h:panelGroup rendered="#{not empty facesContext.messageList or userController.stateManager.failure}">
<!--render error message right here-->
</h:panelGroup>
<div>
<label>#{messages['br.com.spa.domain.model.User.name']}</label>
<h:inputText value="#{user.name}"/>
</div>
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
</form>
</h:body>
Notice that our form will be rendered when a flag create is true - See second line above. To wrap our flags, we create a classe named StateManager as follows
/**
* I am using lombok, which takes care of generating our getters and setters. For more info, please refer http://projectlombok.org/features/index.html
*/
#Setter #Getter
public class StateManager {
private boolean create;
private boolean edit;
private boolean list;
}
Now, because we are using only a single page, we should use a ViewScoped managed bean, which keep our managed bean scoped active as long as you are on the same view - Is it a single page application, right ? So, no navigation. With this in mind, let's create our managed bean.
#ManagedBean
#ViewScoped
public class UserController implements StateManagerAwareManagedBean {
private #Inject UserService service;
private #Getter #Setter stateManager = new StateManager();
private #Getter #Setter List<User> userList = new ArrayList<User>();
private #Getter #Setter User user;
#PostConstruct
public void initialize() {
list();
}
public void create() {
service.persist(user);
stateManager.setCreate(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void edit() {
service.merge(user);
stateManager.setEdit(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void list() {
userList = service.list();
stateManager.setList(true);
}
}
For each action method, we define which piece of our page should be rendered. For instance, consider that our form was processed, covering all of JSF lyfecycle, which implies that their values was successfully converted and validated, and our action method invoked. By using as example our create action method - see above -, we set its create flag as false because our form was converted and validated, so we do not need to show it again (Unless you want). Furthermore, we set both list and success flag as true, which indicates that the list of our page should be rendered and our form was successfully processed - You could use this flag to show something like "User created" such as bellow
<h:panelGroup rendered="#{userController.stateManager.success}">
#{messages['default.created.message']}
</h:panelGroup>
Now, let's discuss which piece of our page should be rendered when it is called for the first time. Maybe you do not know but a void method annotated with #PostConstruct will be called first. So we define which piece of our page should be rendered. In our example, we call list method, which sets its list flag as true and populate a backing list.
#PostConstruct
public void initialize() {
list();
}
Finally, let's review the following order nested within h:commandButton
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
First of all, you should call an ActionListener - here called StateManagerActionListener - which takes care of resetting any StateManager - code bellow. It must be called first before any other setPropertyActionListener designed to control any flag because the order defined within h:commandButton is the order in which they will be called. keep this in mind.
public class StateManagerActionListener implements ActionListener {
public void processAction(ActionEvent e) throws AbortProcessingException {
Map<String,Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
for(Map.Entry<String,Object> entry: viewMap.entrySet()) {
if(entry.getValue() instanceof StateManagerAwareManagedBean) {
((StateManagerAwareManagedBean) entry.getValue()).setStateManager(new StateManager());
}
}
}
}
StateManagerAwareManagedBean - used in our ViewScoped Managed bean -, which allows that we reset any StateManager of any ManagedBean instead of resetting one by one in our ActionListener, is defined as follows
public interface StateManagerAwareManagedBean {
StateManager getStateManager();
void setStateManager(StateManager stateManager);
}
Second, after defining our ActionListener, we use a setPropertyActionListener which set the flag which controls the enclosing piece of the view as true. It is needed because our form is supposed to be not converted and validated. So, in our action method, we set this flag as false as discussed before.
A couple of notes
User is marked as a RequestScoped ManagedBean so that it can not be injected into a ViewScoped one using a ManagedProperty because its scope is shother. To overcome this issue, i set its value by using a <f:setPropertyActionListener target="#{userController.user}" value="#{user}"> - See our form
Our example use JEE features which need a proper Application Server. For more info, refer http://docs.oracle.com/javaee/6/tutorial/doc/
ManagedBean can play different roles such as a Controller, DTO and so on. When it play a role of a Controller, i prefer suffix its name with Controller. For more info, refer http://java.dzone.com/articles/making-distinctions-between
I'm looking for some piece of code for setting a property in a JSF managed bean. My first idea was something like that:
<c:set var="#{loginBean.device}" value="mobil"></c:set>
That means I want to set the attribute device to the value "mobil" without a button have to been clicked.
Yes, you can use c:set for this purpose.
<c:set value="mobil" target="#{loginBean}" property="device" />
Doc: http://docs.oracle.com/cd/E17802_01/j2ee/javaee/javaserverfaces/2.0/docs/pdldocs/facelets/c/set.html
However, setting a static value rarely makes sense. You might consider to set a default value directly in your managed bean class. Also in terms of maintainability since you can handle constants better in the Java code than in the view layer.
I think you want the JSF tag child tag setPropertyActionListener. You can set this as a child tag in any ActionComponent.
<h:anyActionComponent id="component1">
<f:setPropertyActionListener target="#{loginBean.device}" value="mobil" />
</h:anyActionComponent>
UPDATE:
I originally misunderstood the users problem. They have a page, and they want a property to be set when the page loads. There is a couple ways to do this, but both are a little different. If you want to set a property to a value after every postback then you can use the #PostConstruct annotation on a ManagedBean method.
#PostConstruct
public void initializeStuff() {
this.device = "mobil";
}
Now if I have a ViewScoped or SessionScope bean that needs to be initialized with a default value just once when the page loads then you can set a phase lifecycle event that will run after every postback and check to see if the page should be initialized or not.
mah.xhmtl:
<f:event listener="#{loginBean.initialize()}" type="preRenderView" />
LoginBean:
public void initialize() {
if (this.device == null)
this.device = "mobil";
}
I am not able to Comment: If you need the value to be ready on page on load, you could use Managed Bean to directly initialize value or use its constructor or #PostConstruct to do the same.
#ManagedBean
#ResquestScoped
public class LoginBean {
private String device = "some value";
//Using Constructor
public LoginBean() {
device = getvalueFromSomewhere();
}
//Using PostConstruct
#PostConstruct
public void init() {
device = getvalueFromSomewhere();
}
}
Instead of setting the value in the xhtml file you can set via another ManagedBean. For instance if you have managedBean1 which manages page1.xhtml and managedBean2 which manages page2.xhtml. If page1.xhtml includes page2.xhtml like:
<ui:include src="page2.xhtml"/>
in managedBean1 you can have at the top
#ManagedProperty(value = "#{managedBean2}")
private ManagedBean2 managedBean2;
and in the PostConstruct
#PostConstruct
public void construct() {
managedBean2.setProperty(...);
}
worked for me anyway...