In JSF, how can I invoke method in case of conversion failing on any of input fields? I guess I can write my own converters and do all the stuff there, but isn't there a more simple way?
You could use a PreRenderViewEvent listener, and in that method check if validation has failed. This listener method will be called every time just before the view is rendered.
E.g.
Consider the following Facelet:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h:messages/>
<f:event listener="#{onErrorBean.onPreRenderView}" type="preRenderView" />
<h:form>
<h:inputText value="#{onErrorBean.test}" label="test" required="true" />
<h:commandButton value="Submit" action="#{onErrorBean.onSuccess}" />
</h:form>
</h:body>
</html>
And the following backing bean:
#ViewScoped
#ManagedBean
public class OnErrorBean {
private String test;
public void onPreRenderView() {
if (FacesContext.getCurrentInstance().isValidationFailed()) {
onError();
}
}
public void onSuccess() {
System.out.println("Success!");
}
public void onError() {
System.out.println("Error!");
}
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
}
If you press the button without entering a value you'll see "Error!" being printed in your console, enter a value and you'll see "Success!".
Related
I have a JSF2 application that should show a page where a number os items must be added in a list. The user wants to add those items, set some properties of them and finally persist them all together, in a single save operation.
The domain object that should be handled by this page looks like this:
public class Item {
private long id;
private String name;
private Item previous;
public Item() { }
public Item(Item previousItem) {
this.previous = previousItem;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Item getPrevious() {
return previous;
}
}
The ItemBean class looks like this:
#ManagedBean
public class ItemBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<Item> items = new ArrayList<Item>();
public List<Item> getItems() {
if(items.size()==0) {
items.add(new Item()); // adding the first item
}
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
public void addItem(Item previousItem) {
Item newItem = new Item(previousItem);
items.add(newItem);
}
public void save() {
...
}
}
The view is a xhtml file that looks like this:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets">
<body>
<ui:composition template="/templates/layout.xhtml">
<ui:define name="content">
<h2>Items</h2>
<fieldset>
<legend>Items being added</legend>
<ui:repeat value="#{itemBean.items}" var="item">
<div>
<h:outputLabel value="Item" for="name" />
<h:inputHidden value="#{item.id}" />
<h:inputText id="name" value="#{item.name}" />
<h:commandLink action="#{itemBean.addItem(item)}">Add</h:commandLink>
</div>
</ui:repeat>
</fieldset>
<div class="options">
<h:commandButton action="#{itemBean.save}" value="Save"/>
<div class="clear border-bottom"></div>
</div>
</ui:define>
</ui:composition>
</body>
</html>
Notice that in order to add a new item, the current one must be sent to satisfy business rules.
The problem is that I can add a second item with no problema, but when I click in the Add link next to the second item, the page is rerendered with one single item, just like it was in the beggining.
Unfortunatelly, I can't see what's missing to make it work, even after reading a lot of posts, pages and some book chapters.
Update 1
I was asked about the kind of scope used with this bean. It´s de default scope (#RequestScoped). I was trying to avoid using #SessionScoped for the sake of scalability, but in this particular case, I´m not sure I have a choice. Anyone with more experience could give me tip?
What is the scope of your ManagedBean ?
Since you didn't post any persistence code, I suppose the items List only exists througout your Bean's life. This means that if your Bean is #ViewScoped or #RequestScoped, your items cease to exist after you submit your form.
You need use an ajax component, something like:
<fieldset id="list">
<legend>Items being added</legend>
<ui:repeat value="#{itemBean.items}" var="item">
<div>
<h:outputLabel value="Item" for="name" />
<h:inputHidden value="#{item.id}" />
<h:inputText id="name" value="#{item.name}" />
<h:commandLink action="#{cargoBean.addItem(item)}">
<f:ajax render="list" />
Add
</h:commandLink>
</div>
</ui:repeat>
</fieldset>
I see no form in your xhtml page like :
<h:form>
<ui:repeat>
<h:inputBlabla/>
</ui:repeat>
</h:form>
A form is needed while using h:input fields.
I'm using JSF2.1. I don't have any jars in my WEF-INF folder. My classpath is only referencing JSF2.1 and Java EE. I'm using JDK1.7.
I'm getting "Missing Resource in EL implementation: ???propertyNotReadable???" when trying to test out processing GET parameters using f:event type="preRenderComponent". Right now I'm just trying to do a simple test. My page has a lot on it, so I'm only showing the important parts here. The part I added is the <f:metadata> block. When I remove that block, the error goes away.
<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:c="http://java.sun.com/jsp/jstl/core">
<f:metadata>
<f:viewParam name="team" value="#{appBean.team}" />
<f:event type="preRenderComponent" listener="#{appBean.init}" />
</f:metadata>
In my backing bean, I have:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class AppBean implements Serializable{
private static final long serialVersionUID = 1778234L;
private Long team;
public AppBean(){
}
public void init(){
if (team != null) System.out.println(team);
else System.out.println("team undefined");
}
public void setTeam(Long team){
this.team = team;
}
}
And the way I'm testing this out is to go to my url and add ?team=123 to the end. I'm expecting System.out to print 123. Any ideas on how to fix this error?
I figuered it out... I forgot to include:
public Long getTeam(){
return team;
}
i wish to retrieve List based on the selection of dropdownlist item. for that i am using the following code which is not working:
<p:selectOneMenu style="width: 150px" value="#{watchBean.exchange}">
<f:selectItem itemLabel="NSE" itemValue="nse"/>
<f:selectItem itemLabel="BSE" itemValue="bse"/>
<p:ajax event="change" update=":frm" listener="#{watchBean.doScripList}" />
</p:selectOneMenu>
bean code:
public void doScripList(ValueChangeEvent e)
{
sl=getAllScripByExchange((String)e.getNewValue()); //sl is of type List<MasterScrip>
}
when i debug , i see that the event is not fired and i get the following error:
javax.el.MethodNotFoundException: Method not found: beans.watchBean#9ac2e4.doScripList(javax.faces.event.AjaxBehaviorEvent)
at com.sun.el.util.ReflectionUtil.getMethod(ReflectionUtil.java:155)...
when i omit p:ajax the 'exchange' type is also not get/set
what is causing this problem? what is its solution?
edited
renamed the method to wow() still the same error :
javax.el.MethodNotFoundException: Method not found: beans.watchBean#1732d83.wow(javax.faces.event.AjaxBehaviorEvent)
edited : managed bean code
import java.util.List;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.xml.ws.WebServiceRef;
import service.MasterScrip;
import service.StatelessWebService_Service;
#Named(value = "watchBean")
#RequestScoped
public class watchBean {
#WebServiceRef(wsdlLocation = "WEB-INF/wsdl/localhost_8080/StatelessWebService/StatelessWebService.wsdl")
private StatelessWebService_Service service;
/** Creates a new instance of watchBean */
public watchBean() {
}
String uname,scripSym,exchange;
Integer scripID;
List<UserTrack> ut;
List<MasterScrip> sl;
public List<MasterScrip> getSl() {
return sl;
}
public void setSl(List<MasterScrip> sl) {
this.sl = sl;
}
public String getExchange() {
return exchange;
}
public void setExchange(String exchange) {
sl=getAllScripByExchange(exchange);
this.exchange = exchange;
}
public void wow(ValueChangeEvent e)
{
sl=getAllScripByExchange((String)e.getNewValue());
// setSl(sl);
//FacesContext.getCurrentInstance().renderResponse();
// sl=getAllScripByExchange(exchange);
}
Try changing
<p:ajax event="change" update=":frm" listener="#{watchBean.doScripList}" />
to
<p:ajax event="change" update=":frm" listener="#{watchBean.doScripList()}" />
add parenthesis at the end of the method.
JSF is looking for a method setDoScripList in your backing bean, but when adding the parenthesis at the end you're calling this method doScripList explicitly.
Landed on the same problem as yours, but I figured out that the valueChangeListener
public void doScripList(ValueChangeEvent e)
works only when you use <f:ajax> tag and not when you use <p:ajax>.
But since selectOneMenu is of type <p:selectOneMenu>, so <f:ajax> won't work.
I worked out by removing the parameter ValueChangeEvent e and it worked.
So try out a no-parameter listener in case of <p:ajax> tag.
public void doScripList()
{
sl=getAllScripByExchange(getExchangeName());
}
Note: here you don't have the event parameter so, it sets the new value by calling respective setter methods, and you can access updated values in the listener.
For this case you also need to provide id to selectOneMenu like this:
<p:selectOneMenu id="exchangeName" style="width: 150px" value="#{watchBean.exchange}">
...
</p:selectOneMenu>
and then you add get and set methods for exchangeName in your Bean class:
private String exchangeName;
public String getExchangeName(){
return exchangeName;
}
public void setExchangeName(String exchangeName) {
this.exchangeName = exchangeName;
}
It is primefaces 3.2 bug, please replace your code as the following.
<h:selectOneMenu style="width: 150px" value="#{watchBean.exchange}" valueChangeListener="#{watchBean.doScripList}" onchange="submit()">
<f:selectItem itemLabel="NSE" itemValue="nse"/>
<f:selectItem itemLabel="BSE" itemValue="bse"/>
</h:selectOneMenu>
Change your method likes here;
public void doScripList(ValueChangeEvent e){
sl = getAllScripByExchange((String)e.getNewValue());
setAllScriptExchange(sl); //please write setAllScriptExchange method yourself
FacesContext.getCurrentInstance().renderResponse();
}
Your page is reloaded, because of onchange event.
how to move a variable's value from jsf's bean page (i.e, bean.java) to another java class? when i tried to do that, the value assinged to the variable in the second java class is NULL.,
I have used primefaces UI framework(something like jsf) and assigned every fields value in to a bean class. the value assigned to every variable in bean class is proper. but when i tried to move those values to another .java file. The scope of the variable dies, and the value is NULL. Check out my codings..
LOGIN.XHTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.prime.com.tr/ui">
<h:head></h:head>
<h:body>
<p:panel header="Login" style="">
<h:form>
<h:panelGrid columns="2" cellpadding="2">
<h:outputText value="Username"></h:outputText>
<p:inputText id="userName" value="#{loginBean.userName}"></p:inputText>
<h:outputText value="Password"></h:outputText>
<p:password id="password" value="#{loginBean.password}"></p:password>
<p:commandButton value="Sign in" ajax="false" actionListener="#{loginBean.forward}"></p:commandButton>
</h:panelGrid>
</h:form>
</p:panel>
</h:body>
</html>
loginBean.java
package bean;
import receive.*;
public class loginBean {
public String userName;
public String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void forward()
{
System.out.println(getUserName());
receiveclass r=new receiveclass();
r.dbc();
}
}
receiveclass.java
package receive;
import bean.loginBean;
public class receiveclass {
loginBean lb=new loginBean();
public void dbc()
{
String s= lb.getUserName();
String p=lb.getPassword();
System.out.println(s);
System.out.println(p);
//System.out.println("hi");
}
}
output is,
if i give as admin, admin in text fields
i am receiving as
admin
null
null
You're manually creating the beans instead of letting JSF manage the beans. Manually created beans won't be used by JSF at all. You need to let JSF auto-create and manage those beans. You can access other JSF managed beans by injecting it as #ManagedProperty:
In your particular case, the following should work:
#ManagedBean
#RequestScoped
public class LoginBean {
private String userName;
private String password;
#ManagedProperty
private ReceiveClass receiveClass;
public void forward() {
receiveClass.dbc(this);
}
// Add/generate getters and setters.
}
with
#ManagedBean
#SessionScoped
public class ReceiveClass {
public void dbc(LoginBean loginBean) {
System.out.println(loginBean.getUserName());
}
}
(Note that I fixed the code to adhere the Java Naming Conventions properly. Class names ought to start with uppercase)
See also:
Communication in JSF 2.0 - Injecting managed beans in each other
in your receiveclass you create a completely new instance of loginBean. Values can only be null.
I do it this way: I created a Java class in which I have static functions like this one
public class JSFHelper
{
public static Object getMyObject(String objname, Class<?> classname )
{
FacesContext fCtx = FacesContext.getCurrentInstance();
ELContext elCtx = fCtx.getELContext();
ExpressionFactory ef = fCtx.getApplication().getExpressionFactory();
ValueExpression ve =
ef.createValueExpression(elCtx, "#{" + objname+ "}",classname);
return (Object) ve.getValue(elCtx);
}
}
If I need a value from another Bean it would look like this in your receiveclass:
public class receiveclass
{
public void dbc()
{
loginBean lb=(loginBean)JSFHelper.getMyObject("loginBean",loginBean.class);
String s= lb.getUserName();
String p=lb.getPassword();
System.out.println(s);
System.out.println(p);
//System.out.println("hi");
}
}
I have <h:inputText> on form and what I need is to execute some method from backing bean on BLUR event:
public void test()
{
System.out.print("HELLO!");
}
Can you help me?
You can use <f:ajax>
<h:form>
<h:inputText value="#{managedBean.val}" >
<f:ajax event="blur" render="result" listener="#{managedBean.test}"/>
</h:inputText>
</h:form>
#ManagedBean(name = "managedBean")
public class Bean {
private String val; // getter and setter
...
public void test() {
System.out.print("HELLO!");
}
}
Alternative :
If you are using richfaces then you can use a4j:jsFunction
See Also
JSF2: Ajax in JSF – using f:ajax tag
How-to-update-a-value-displayed-in-the-page-without-refreshing