Validation of ViewParam and a4j:commandButton - jsf

I think i came across a bug of #ViewScoped with a4j:commandButton.
I have a very complex form where all actions use a4j, except those that need to upload data.
And depending on the order of the commands the validation of the viewParam breaks.
Here is the working code:
<?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:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j" >
<f:metadata>
<f:viewParam id="viewParam" name="viewParam" value="#{bean.viewParam}" required="true" />
</f:metadata>
<h:head>
<title>Test View Param</title>
</h:head>
<h:body>
<h:message for="viewParam" />
<hr/>
<h:form>
#{bean.viewParam}<br/>
<h:commandButton value="cmdButton" />
<a4j:commandButton value="a4jBtn" execute="#this" render="#form" />
</h:form>
</h:body>
</html>
just click on the a4jBtn and then on the cmdButton to see the problem.
you will see that the parameter is still there! but that the validation fails.
<t:saveState> does not help,
<rich:message> is also not better, but
<h:commandButton value="ajaxBtn" ><f:ajax execute="#this" render="#form" /></h:commandButton>
instead of
<a4j:commandButton value="a4jBtn" execute="#this" render="#form" />
does work correctly!
Using myFaces 2.0.15 and richFaces 4.2.3.Final on Tomcat 6.0.18 and jboss-el 2.0.0.GA.
i could workaround my problem by using f:ajax instead of a4j:commandButton, but maybe you have a better idea, or you could just explain to me what is going wrong?

You basically need to retain the view parameters on synchronous postbacks. As you're using OmniFaces, you could use <o:form> for that.
<o:form includeViewParams="true">
Or as you're already using a view scoped bean, trigger the validation only on non-postbacks.
<f:viewParam ... required="#{not facesContext.postback}" />
Or, as you're using OmniFaces, you could use <o:viewParam> instead which skips the validation/conversion/update on postbacks.
<o:viewParam ... />

Related

Primefaces blockUI and composition

I'm using JSF 2.2, PF 5.3 and GlassFish 4.1.1.
I'm trying to centralize the blockUI content in my web application.
here the code of the my custom blockUI
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:p="http://primefaces.org/ui">
<cc:interface>
<cc:attribute name="block" type="java.lang.String"/>
<cc:attribute name="trigger" type="java.lang.String"/>
</cc:interface>
<cc:implementation>
<p:blockUI block="#{cc.attrs.block}" trigger="#{cc.attrs.trigger}">
LOADING<br />
<p:graphicImage library="images" name="ajax-loader.gif"/>
</p:blockUI>
</cc:implementation>
and here the code in which I'm trying to apply this one
<h:form>
...
...
<p:dataTable id="myTable">
<p:column headerText="actions">
<p:commandButton class="triggerableFromBlockUI" action="#{action1}"/>
<p:commandButton class="triggerableFromBlockUI" action="#{action2}"/>
</p:column>
</p:dataTable>
...
...
<myTag:blockUI block="myTable" trigger="#(.triggerableFromBlockUI)"/>
</h:form>
but I see the following error
Cannot find component for expression "myTable".
If I use directly the p:blockUI all is working. Can you help me?
Here the solution found in the Prime Faces Forum
<myTag:blockUI block="#form:myTable" trigger="#(.triggerableFromBlockUI)"/>

Getting page parameters for a requestscoped bean in a form

I have the following page:
<?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:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>Fire - Registration</title>
</h:head>
<h:body>
<f:view>
<f:event type="preRenderView" listener="#{confirmPasswordResetBean.bindSessionKey()}"/>
</f:view>
<p:growl id="growl" showDetail="true" life="5000" />
<h:form>
<p:panel header="Select your new password">
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel for="newPassword" value="Type your new password"/>
<p:password id="newPassword"
value="#{confirmPasswordResetBean.firstPassword}"
feedback="true"/>
<p:outputLabel for="retypedPassword" value="Retype your password"/>
<p:password id="retypedPassword"
value="#{confirmPasswordResetBean.secondPassword}"/>
</h:panelGrid>
<p:commandButton id="confirmButton"
value="reset"
action="#{confirmPasswordResetBean.doResetPassword()}"
update=":growl"/>
</p:panel>
</h:form>
</h:body>
The backing bean used above is RequestScoped, and the page itself takes a single parameter (sessionKey)...what I want to do is to:
1. Bind sessionKey to a variable in the backing bean. This is straightforward enough.
2. Use the bound value of sessionKey when executing dedicated logic in the same bean, when the client presses the commandButton.
The problem is that pressing the button starts a new request, which invalidates both the current bean (with the bound value), as well as the external page context...I thus lose all means to get a hold of sessionKey from either the bean or the page parameters...how can I resolve this? I am relatively new to both web programming and JSF, so pardon me if this has an obvious answer.
Either put the bean in the view scope, so that it lives long as you're interacting with the same view, or pass the request parameter by <f:param> to the subsequent requests.
<p:commandButton ...>
<f:param name="sessionKey" value="#{param.sessionKey}" />
</p:commandButton>
By the way, you'd rather have used <f:viewParam> to bind the request parameter to the bean directly.
<f:metadata>
<f:viewParam name="sessionKey" value="#{bean.sessionKey}" />
</f:metadata>
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?

How to create links relative to the right context?

I have this composition :
<!DOCTYPE html>
<ui:composition 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">
<h:panelGroup rendered="#{empty userc.userb.user.id}">
<h:panelGrid columns="2" >
<h:outputLink value="system/register.xhtml">Register</h:outputLink>
<h:outputLink value="system/login.xhtml">Login</h:outputLink>
</h:panelGrid>
</h:panelGroup>
</ui:composition>
If the user click in Login the page is redirect to system/login.xhtml, which is correct, but if the user, click in Login again, it is redirect to system/system/login.xhtml.
I know a solution for this, which BalusC help me out a long time ago:
<base href="#{fn:replace(request.requestURL, fn:substring(request.requestURI, 1, fn:length(request.requestURI)), request.contextPath)}/" />
It solve my problem, but if I have some ManageBean instancied when I click in some link the bean it's invalidate.
How mantain the url path in every link page and keep the session in the Managed beans ?
Use <h:link> instead. JSF will append the right context path and FacesServlet mapping.
<h:link value="Register" outcome="/system/register" />
<h:link value="Login" outcome="/system/login" />
See also:
Communication in JSF 2.0 - Implicit navigation

Making p:commandButton work like h:button

I have this working code in my webapp:
<h:button value="Edit user..." outcome="/public/user" >
<f:param name="userName" value="#{authBean.authUser}"/>
</h:button>
What it does:
It makes the button send a GET
It passes the specified parameter in the URL, making it bookmarkable.
What I need:
It should work like h:button above (send GET)
the button should look like other Primefaces buttons (eg. decorated with an image... etc).
This is the closest I could get:
<p:commandButton value="Edit user..." action="/public/user?faces-redirect=true" ajax="false" immediate="true" >
<f:param name="userName" value="#{authBean.authUser}"/>
</p:commandButton>
It sends a POST that gets redirected to the new URL with a GET. However the parameter is lost in the process.
Another idea:
<p:linkButton value="Edit user..." href="http://localhost:8080/contextpath/faces/public/user.xhtml">
<f:param name="userName" value="#{authBean.authUser}"/>
</p:linkButton>
The GET request is aborted (??? according to Firebug) and the current page is POSTed again.
What is the proper way of doing this?
UPDATE: this works (on an empty page, with no p:dataTable):
<p:linkButton value="Edit user..." href="http://localhost:8080/contextpath/faces/public/user.xhtml?userName=myusername">
but this does not:
<p:linkButton value="Edit user..." href="http://localhost:8080/contextpath/faces/public/user.xhtml?userName=myusername&secondParam=otherValue">
the latter results in:
500: javax.servlet.ServletException:
Error Parsing /sample0.xhtml: Error
Traced[line: 14] The reference to
entity "secondParam" must end with the
';' delimiter.
UPDATE2: the & should be escaped:
<p:linkButton value="Edit user..." href="http://localhost:8080/contextpath/faces/public/user.xhtml?userName=myusername&secondParam=otherValue">
and it looks good... but I still get the GET aborted and POST resent:
alt text http://img64.imageshack.us/img64/1017/primefaceslinkbutton.jpg
This is the full empty page I've been trying it with:
<?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:c="http://java.sun.com/jsp/jstl/core"
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:body>
<h:form>
<p:linkButton value="Click me" href="http://stackoverflow.com" />
</h:form>
</h:body>
</html>
Primefaces 2.1 release.
In PrimeFaces 2.2., we'll deprecate linkButton and introduce p:button. Issue ticket;
http://code.google.com/p/primefaces/issues/detail?id=1037
Use p:linkButton.
Update: as per your update with the code example, the URL should be specified in href attribute, not in the url attribtue. Also see the component's documentation which I linked here above.
The symptoms at least sounds like as if you're firing an asynchronous (Ajax) GET request, not a synchronous one. FireBug would then indeed give this kind of error when the request is fired on a different domain.
Don't you have some other Javascripts which are disturbing/colliding with the linkButton's default behaviour? The button is navigating by a simple onclick="window.location=newurl;".
Update 2: does it work if you test it standalone in a simple page? E.g.
<!DOCTYPE html>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui">
<h:head>
<title>Test</title>
</h:head>
<h:body>
<p:linkButton value="test" href="http://stackoverflow.com" />
</h:body>
</html>

JSF Navigation issue Facelets and Beans

I have an issue with navigation in my simple jsf system.
I have MainBean that has two methods: public String register() and public String login().
I have played with faces-config.xml for several hours and I feel like I miss something very important because I think like I have tried all simple solutions so far :).
I have added the MySQL connector (jdbc) to Tomcat's lib folder and I am able to register the table to MySQL database. It even allows my users to log in to the page.
The only problem is that I can't use navigation in any other page than login.xhtml. Seems like navigation is only active on this one. I tried to use <from-view-id>* but is no joy. I am sure that there is a simple fix for that and someone will come up with correct solution soon. Let's skip all the MySQL part and try to fix the navigation issue please.
Here is the faces-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
<application>
<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
</application>
<managed-bean>
<managed-bean-name>mainBean</managed-bean-name>
<managed-bean-class>dk.itu.beans.MainBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>registerBean</managed-bean-name>
<managed-bean-class>dk.itu.beans.RegisterBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id>/login.xhtml</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/welcome.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>failure</from-outcome>
<to-view-id>/login_failed.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>sign</from-outcome>
<to-view-id>/register.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/login_failed.xhtml</from-view-id>
<navigation-case>
<from-outcome>back</from-outcome>
<to-view-id>/login.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
Here the last navigation-rule from login_failed.xhtml does not work at all.
Here is login.xhtml (which is the main - starting view):
<!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">
<body>
<ui:composition template="/template.xhtml">
<ui:define name="body">
<h:form id="helloForm">
<h:panelGrid columns="2">
<h:outputText value="Username2:" />
<h:inputText id="username" value="#{mainBean.username}" />
<h:outputText value="Password:" />
<h:inputSecret id="password" value="#{mainBean.password}" />
</h:panelGrid>
<h:commandButton value="Log in" action="#{mainBean.login}" />
<h:commandButton value="Sign up" action="sign" />
</h:form>
</ui:define>
</ui:composition>
</body>
</html>
login_failed.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">
<body>
<ui:composition template="/template.xhtml">
<ui:define name="body">
<f:view>
<h:outputText value="Unknown username or password." />
<h:commandButton value="Sign up" action="sign" />
<h:commandButton value="Log in" action="back" />
</f:view>
</ui:define>
</ui:composition>
</body>
</html>
Here I tried many options. I used action="#{mainBean.register})" method that returns "sign" string and none of these worked. There is one more file (not specified in faces-config.xml file, because did not work either - but going from login.xhtml by button works fine. I tried to manage navigation from login_failed.xhtml first, then I will apply the same rule for registration to come back to login page when customer registers his nick name).
Here is register.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">
<body>
<ui:composition template="/template.xhtml">
<ui:define name="body">
<h:form id="helloForm">
<h:panelGrid columns="2">
<h:outputText value="User Name:"/>
<h:inputText type="text" id="userName" value=""/>
<h:outputText value="Password:"/>
<h:inputSecret type="text" id="userPassword" value=""/>
<h:outputText value="Member Level:"/>
<h:selectOneRadio value="">
<f:selectItem itemLabel="Platinium" itemValue="Platinum" />
<f:selectItem itemLabel="Gold" itemValue="Gold" />
<f:selectItem itemLabel="Normal" itemValue="Normal" />
</h:selectOneRadio>
<h:outputText value="Full Name:"/>
<h:inputText type="text" id="userFull" value=""/>
<h:outputText value="Address:"/>
<h:inputTextarea type="text" id="userAddress" value=""/>
<h:outputText value="Zip Code:"/>
<h:inputText type="text" id="userZip" value=""/>
<h:outputText value="City:"/>
<h:inputText type="text" id="userCity" value=""/>
<h:commandButton value="Sign Up" action="#{mainBean.register}" />
</h:panelGrid>
</h:form>
</ui:define>
</ui:composition>
</body>
</html>
Basicaly mainBean.register now calls the database and returns string, but obviously it doesn't navigate to any view (but gives an entry to database).
I believe it is simple fix for most of the experienced web developers and any help will be greatly appreciated.
I use eclipse, tomcat 6 and Widows Vista if that helps :)
Thank you in advance.
Kindest regards.
In general I can recommend trying to get something simple working prior to moving on to the advanced stuff like templating. A few pointers:
Use redirect in the navigation rule on the login page. This way you don't need any special hoopla to get the back button working.
Its generally a bad idea to create the session bean prior to the login being validated. A common solution is to use a request scoped identity bean on the login page, then inject this into a LoginAction which validates the credentials and creates the user session.
I have a rather complete Facelets/JSF2 sample online that demonstrates this behaviour:
Facelets login login.xhtml and welcome.xhtml page
JSF faces-config.xml
Request scoped identity bean and the login action that validates user credentials.
Feel free apply the copy-paste design pattern to your code as much as you like.
UICommand components ought to be placed inside an UIForm element. In login_failed.xhtml you're forgotten use a h:form. Add it and it will work.

Resources