I'm unable to pass a simple parameter from one Facelet to another, and set a bean property...here's my code:
The calling page, main.xhtml (only relevant code):
<h:link outcome="index" value="disconnect" >
<f:param name="logout" value="true" />
</h:link>
The final page, index.xhtml:
<?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://xmlns.jcp.org/jsf/core">
<f:metadata>
<f:viewParam name="logout" value="#{indexBean.logout}"/>
<f:event type="preRenderView" listener="#{indexBean.redirect}" />
</f:metadata>
</html>
And the IndexBean (only relevant code):
#Named
#RequestScoped
public class IndexBean {
#Inject
private Logger logger;
private boolean logout;
public IndexBean() {this.logout = false;}
public void setLogout(boolean logout) {
logger.log(Level.DEBUG, "logout changed");
this.logout = logout;
}
public boolean isLogout() {return logout;}
public void redirect() throws IOException {
if(logout) {
//Never get in here
} else {
//Always here
}
}
}
I'm getting the URL parameter right on the link (http://localhost/index.xhtml?logout=true), but the setLogout method is never called.
I've even tried to change the logout type to String, change getter and setter properly and see what happens, but the setter is never called...
Any idea?
Thanks in advance!!
Related
xhtml file I use a viewParam:
<?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:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<f:metadata>
<f:viewParam name="actionId" value="#{editActionView.actionId}" required="true" />
</f:metadata>
<h:body>
The backing bean looks as follows:
EditActionView.java
#ManagedBean
#ViewScoped
public class EditActionView {
private long actionId;
#PostConstruct
void init() {
System.out.println("actionId: " + getActionId());
}
public long getActionId() {
return actionId;
}
public void setActionId(long actionId) {
this.actionId = actionId;
}
When I now call my application:
http://localhost:8080/aip/editAction.jsf?actionId=37
actionId is always 0. Where is my fault?
The ManagedBean is constructed before the setter is called. Therefore the System.out.println(...) in the #PostConstruct method prints the default value for the actionId of type long which is 0.
The setter is then called in the UPDATE_MODEL_VALUES phase. You can check this by putting another System.out.println(...) in the setter method, which should print the correct value.
I've the below portlet view.xhtml:
<?xml version="1.0"?>
<f:view xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:body>
<h:form>
<h:commandButton value="TESTButton" action="#{navigationViewBean.submit}" />
<h:outputText value="TESTGetter: #{navigationViewBean.testField}" />
</h:form>
</h:body>
</f:view>
And this managed bean:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean(name = "navigationViewBean")
#RequestScoped
public class NavigationViewBean {
private String testField;
public boolean lol = false;
public void submit() {
System.out.print("TEST BUTTON INVOKED");
}
public String getTestField() {
System.out.print("TEST GETTER INVOKEDx");
return testField;
}
public void setTestField(String testField) {
this.testField = testField;
}
}
The only thing I try to do, is to call a method which prints something to my console. The problem is that no matter what I do, the action method is never invoked. The getter method is properly called.
What am I doing wrong?
Im not sure why, but after adding this line to my liferay-portlet.xml it fixed it.
<requires-namespaced-parameters>false</requires-namespaced-parameters>
And here the whole block:
<portlet>
<portlet-name>Test1</portlet-name>
<icon>/icon.png</icon>
<requires-namespaced-parameters>false</requires-namespaced-parameters>
<header-portlet-css>/css/main.css</header-portlet-css>
</portlet>
I found a weird behavior in JSF/PrimeFaces and ask your help to understand and get around it. The actionListener method in a commandButton is executed just once.
Contextualization:
I put a link in start page of my project to a second page, renderized as follows:
http://localhost:8080/MeusTestes-war/faces/somepage.xhtml?id=1
Notice there is a parameter sent by query string.
The somepage.xhtml:
<?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:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Facelet Title</title>
</h:head>
<f:metadata>
<f:viewParam name="id" value="#{someBean.id}" required="true" />
<f:viewAction action="#{someBean.init}" />
</f:metadata>
<h:body>
<h:form id="form1">
<p:commandButton id="teste1"
value="Teste"
actionListener="#{someBean.doTeste}" />
</h:form>
</h:body>
</html>
As you can see, its extremely simple. Notice there is a metadata section doing the parameter reception and the execution of init() method. In page body there is a p:commandButton and a actionListener pointing to doTeste().
There is my Bean:
#Named(value = "someBean")
#ViewScoped
public class SomeBean implements Serializable {
private int id;
public SomeBean() {
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public void init() {
System.out.println("init " + id);
}
public void doTeste(ActionEvent actionEvent) {
System.out.println("doTeste " + id);
}
}
Well, now the mysterious behavior:
1) When page is loaded, as expected, the init() method shows a message with the correct property value got by viewParam.
2) Firing the button, as expected too, the doTeste() method shows a message with the correct property value.
However,
3) Firing the button again, nothing happens!
Other facts:
If I remove the metadata section the doTeste() method is executed as many times as the button is clicked, which is supposed to happen. But the property, obviously, is not initialized.
If I switch the button definition from p:commandButton to h:commandButton, the doTeste() method is executed as expected AND the property is initialized. But I lose the PrimeFaces pattern.
My question:
How to do the commandButton actionListener from PrimeFaces behave the way is expected? (executing the method each time it is fired)
Thanks!
If you for testing purposes add a <p:growl id="msgs"/> and add update="msgs" to the button you'll see that validation fails on subsequent requests (because of required="true" on the viewParam).
So you can either
remove required="true". Probably a bad idea since you need it.
add the parameter to the commandButton with <f:param name="id" value="#{someBean.id}"/>
use OmniFaces <o:viewParam>.
There is a more technical explanation here.
I'm trying to convert GET request parameters passed from another view like this:
<f:metadata>
<f:viewParam name="id"
value="#{targetViewBean.fooFromSourceView}"
converter="fooConverter"
converterMessage="Foo converter message"
required="true" requiredMessage="Foo required message"/>
<f:viewAction action="#{targetViewBean.doSomethingWithFoo()}"/>
</f:metadata>
But only the Converter.getAsString(..., Object value) method is called and value is always null, even thou the GET parameter is really sent.
I found BalusC blog post about this and, AFAIK, I followed it to the letter. Still no good. Here's the full code:
Source view
<h:head>
<title>Source view</title>
</h:head>
<h:body>
<ul>
<ui:repeat value="#{sourceViewBean.foos}" var="foo">
<li>
<h:link value="Foo \##{foo.id}" outcome="target-view">
<f:param name="id" value="#{foo.id}" />
</h:link>
</li>
</ui:repeat>
</ul>
</h:body>
Backing bean
#Named #ViewScoped
public class SourceViewBean implements Serializable {
public Collection<Foo> getFoos() {
return Db.INSTANCE.getFoos();
}
private static final long serialVersionUID = 1L;
}
Target view
<f:metadata>
<f:viewParam name="id"
value="#{targetViewBean.fooFromSourceView}"
converter="fooConverter"
converterMessage="Foo converter message"
required="true" requiredMessage="Foo required message"/>
<f:viewAction action="#{targetViewBean.doSomethingWithFoo()}"/>
</f:metadata>
<h:head>
<title>Target view</title>
</h:head>
<h:body>
<h:outputText value="ID: #{targetViewBean.fooFromSourceView.id}" />
</h:body>
Target view backing bean
#Named
#ViewScoped
public class TargetViewBean implements Serializable {
private Foo fooFromSourceView;
public void doSomethingWithFoo() {
System.out.println("Foo is here? " + fooFromSourceView != null);
}
public Foo getFooFromSourceView() {
return fooFromSourceView;
}
public void setFooFromSourceView(Foo fooFromSourceView) {
this.fooFromSourceView = fooFromSourceView;
}
private static final long serialVersionUID = 1L;
}
The converter
#FacesConverter(value = "fooConverter")
public class FooConverter implements Converter {
#Override
public Object getAsObject(
FacesContext context, UIComponent component, String value) {
if (value == null || !value.matches("\\d+")) {
return null;
}
for (Foo foo : Db.INSTANCE.getFoos()) {
if (foo.getId().equals(Integer.parseInt(value))) {
return foo;
}
}
throw new ConverterException(new FacesMessage("No Foo found!"));
}
#Override
public String getAsString(
FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Foo) || ((Foo) value).getId() == null) {
return null;
}
return ((Foo) value).getId().toString();
}
}
I was able to find the problem after taking a look at the actual code you sent. The issue is not with the converter. It's with the xml namespaces at the top of your project. For instance, in source-view.xml you have
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
But they should be
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core">
And target-view.xhtml should be
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
GlassFish seems to change the namespaces for some reason. I didn't try to find out why it behaves like that though so keep that in mind. Anyway, once I changed it, the correct phases were being outputted in GlassFish's output window. So go and make the necessary change where needed.
Note: In case you are wondering why you are getting the following error
The metadata component needs to be nested within a f:metadata tag. Suggestion: enclose the necessary components within <f:metadata>
This seems to be a reported issue with JSF 2.2
Also, I'm not sure why your h:link is nested inside an h:form. It's not needed.
UPDATE
Seems like some of the taglibs are not fully functional or am I reading this wrong ?
https://java.net/jira/browse/JAVASERVERFACES-2868
I am finding view params will not be passed from a page where the backing bean is different on the target page. How can I pass the product param from test1.xhtml to test2.xhtml?
test.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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui" xmlns:o="http://omnifaces.org/ui">
<body>
<f:metadata>
<o:viewParam name="product" value="#{holder.value}"
converter="#{productConverter}"
converterMessage="Bad request. Unknown product." required="true"
requiredMessage="Bad request. Please use a link from within the system." />
</f:metadata>
<h:link outcome="/test2.xhtml" includeViewParams="true">link</h:link>
</body>
</html>
test2.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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui" xmlns:o="http://omnifaces.org/ui">
<h:head></h:head>
<body>
<f:metadata>
<o:viewParam name="product" value="#{holder2.value}"
converter="#{productConverter}"
converterMessage="Bad request. Unknown product." required="true"
requiredMessage="Bad request. Please use a link from within the system." />
</f:metadata>
<h:link outcome="/test.xhtml" includeViewParams="true">link</h:link>
</body>
</html>
Holder.java
#ManagedBean
#ViewScoped
public class Holder<T> implements Serializable {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
Holder2.java
#ManagedBean
#ViewScoped
public class Holder2<T> implements Serializable {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
Product.java
public class Product {
private String name;
public Product(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
}
Product Converter
public class ProductConverter implements Converter {
private Map<String,Product> productMap=new HashMap<String, Product>();
public ProductConverter(List<Product> products) {
for (Product product:products){
productMap.put(product.getName().toLowerCase(), product);
}
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return productMap.get(value.toLowerCase());
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Product) ) {
return null;
}
return ((Product) value).getName().toLowerCase();
}
}
<h:link outcome="/test2.xhtml?includeViewParams=true">link</h:link>
This is not the right way to let JSF include view parameters in a <h:link>. Supplying it as a query string parameter is only valid in action attribute of UICommand components.
You need the includeViewParams attribute of the <h:link> instead.
<h:link outcome="/test2.xhtml" includeViewParams="true">link</h:link>
#ViewScoped is only valid for postbacks - if you change the URL, the bean dies.
To pass parameters between facelets, use <ui:param>