<f:paramView> redirect with message - jsf-2

I have a JSF 2.1, Primefaces 4.0 web app where I want to pass some values with GET to the managed bean. For this I have used:
<f:metadata>
<f:viewParam name="id" value="#{myMB.queueId}" required="true" requiredMessage="This field is required" converter="javax.faces.Integer" converterMessage="Cannot Convert"/>
<f:event type="preRenderView" listener="#{myMB.init}" />
</f:metadata>
and the managed bean :
public MyMB{
private Integer queueId;
// setters and getters....
public void init(){
FacesContext fc = FacesContext.getCurrentInstance();
if(!fc.isPostback()){
if(fc.isValidationFailed()){
//if validation fails i want to add here a message - Ideally to keep the validation/convertion errors declared in f:viewParam....
FacesMessage fm = new FacesMessage(..put validation error message here...)
fc.add(null,fm);
try {
fc.getExternalContext().redirect("viewQueues.xhtml?faces-redirect=true");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
So i want to send the validation error on the redirected page.
I also tried with :
context.getExternalContext().getFlash().setKeepMessages(true);
but on the redirected page i do not get any message.I have to mention here that on my viewQueues.xhtml i have an tag that should display the errors.
Is there a way to accomplish that ?

Related

How to send a message to the next page in JSF2 using flashScope

I'm using JSF 2.0, primefaces 5 and JBoss AS 6 (at start it displays this message:"[JSFImplManagementDeployer] Initialized 3 JSF configurations: [Mojarra-1.2, MyFaces-2.0, Mojarra-2.0]") and I'm trying to send a message to the next page using JSF2 flashScope.
This is the ManagedBean of the first page:
if (error) {
FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_WARN, "An error has occurred", "Please try again.");
FacesContext facesContext = FacesContext.getCurrentInstance();
Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
flash.setKeepMessages(true);
flash.setRedirect(true);
flash.putNow("message", facesMessage);
facesContext.addMessage(null, facesMessage);
try {
facesContext.getExternalContext().redirect("index.xhtml");
}
catch (IOException ex) {
logger.error("IOException during redirection to the home");
}
}
In my index.xhtml page (that is the page were I want to show the message) I inserted the tag:
...
<ui:define name="top">
<p:messages />
...
The redirection works if an error occurs but the message is not displayed. What is wrong? Have I to write some code in the destination page ManagedBean?

flash message not displaying after redirect from f:phaselistener

I have an issue with understanding how flash works in the jsf lifecycle.
I am trying to redirect to a different page from a phase listener through a normal get request and at the same time adding a flash message(of course i have set the flah.keepmessage) to be displayed on the new page. But the message fails to show up. I know that something is wrong and will be grateful if anyone can kindly assist in implementing a better way (without filters please).
phaseredirect1.html
<h:body>
<f:view>
<f:phaseListener binding="#{testphase.testPL}"/>
<div>Testing Phases Redirect 1</div>
</f:view>
</h:body>
TestPhaseRedirect.java
#SessionScoped
#ManagedBean(name="testphase")
public class TestPhaseRedirect {
private PhaseListener testPL;
#PostConstruct
private void initializeVar(){
testPL = new PhaseListener() {
#Override
public void afterPhase(PhaseEvent event) {
}
#Override
public void beforePhase(PhaseEvent event) {
getFacesContext().addMessage(null, new FacesMessage("Faces Message: redirecting to page 2..."));
getExternalContext().getFlash().setKeepMessages(true);
ConfigurableNavigationHandler nav = (ConfigurableNavigationHandler)getFacesContext().getApplication().getNavigationHandler();
nav.performNavigation("redirect-to-page2");
getFacesContext().responseComplete();
return;
}
#Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
};
}
public PhaseListener getTestPL() {
return testPL;
}
}
phaseredirect2.html
<h:body>
<f:view>
<div style="width:400px;">
<p:messages autoUpdate="true" closable="true"/>
<p>Testing Phases Redirect 2</p>
<p> Did it display the message? </p>
</div>
</f:view>
</h:body>
faces config
<navigation-case>
<from-outcome>redirect-to-page2</from-outcome>
<to-view-id>/phaseredirect2.html</to-view-id>
<redirect />
</navigation-case>
Kindly correct me.
Thank you so much.
During the render response phase, it's too late to create the flash scope. You need to do it at latest during invoke application phase. Basically, this problem has the same grounds as when doing so in a <f:event type="preRenderView"> as already answered in the following related questions:
Adding faces message to redirected page using ExternalContext.redirect()
Mojarra 2.1.14 flash scope messages and redirect to different path
In your particular case, you need a dummy view parameter so that the invoke action phase is triggered and then use the <f:event type="postInvokeAction"> (after having created the custom event yourself or having installed OmniFaces as per the answers on the abovelinked questions):
<f:metadata>
<f:viewParam name="dummy" />
<f:event type="postInvokeAction" listener="#{bean.init}" />
</f:metadata>
with
public void init() {
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, new FacesMessage("Faces Message: redirecting to page 2..."));
context.getExternalContext().getFlash().setKeepMessages(true);
ConfigurableNavigationHandler nav = (ConfigurableNavigationHandler) context.getApplication().getNavigationHandler();
nav.performNavigation("redirect-to-page2");
}
or if you've chosen for OmniFaces
public void init() {
Messages.addFlashGlobalInfo("Faces Message: redirecting to page 2...");
Faces.navigate("redirect-to-page2");
}

composite component button action issue in jsf2 mojarra

Trying to develop a composite component using jsf2.0 (Mojarra) which should render command buttons dynamically based on the list from the bean. I was able to render the buttons but action is not getting triggered.Could any one please help me to resolve the issue?
Here follows the code
<composite:interface>
<composite:attribute name="buttonList" required="true"
type="java.util.List" />
<composite:attribute name="beanName" required="true"
type="java.lang.Object" />
</composite:interface>
<composite:implementation>
<ui:repeat var="listItem" value="#{cc.attrs.buttonList}">
<h:commandButton value="#{listItem.buttonName}"
action="#{cc.attrs.beanName.listItem.buttonAction}">
</h:commandButton>
</ui:repeat>
</composite:implementation>
This is used as
<utils:buttonGroup buttonList="#{testButtonBean.buttonList}"
beanName="#{testButtonBean}" />
The bean looks like
public class TestButtonBean {
public List<ButtonPOJO> buttonList = new ArrayList<ButtonPOJO>();
public List<ButtonPOJO> getButtonList() {
return buttonList;
}
public void setButtonList(List<ButtonPOJO> buttonList) {
this.buttonList = buttonList;
}
public void preProcess() {
if (null != buttonList && buttonList.size() == 0) {
ButtonPOJO ob1 = new ButtonPOJO("Continue", "next");
ButtonPOJO ob2 = new ButtonPOJO("Back", "prev");
buttonList.add(ob1);
buttonList.add(ob2);
}
}
public String next() {
return "page1";
}
public String prev() {
return "page2";
}
}
action="#{cc.attrs.beanName.listItem.buttonAction}"
This is not right. This syntax is basically looking for a property listItem on beanName and then trying to invoke the literal action buttonAction() on it.
You need the brace notation action="#{bean[methodName]}" if you want to specify the action method name as string coming from another bean property.
action="#{cc.attrs.beanName[listItem.buttonAction]}"
Unrelated to the concrete problem, if the above solution still fails, then that can only mean that the value="#{cc.attrs.buttonList}" has incompatibly changed during the form submit request. You need to make sure that exactly the same list is prepared during the postback as it was during the initial request. See also point 4 of commandButton/commandLink/ajax action/listener method not invoked or input value not updated.

Handling view parameters in JSF after post

I have a few pages that needs a userId to work, thus the following code:
userpage.xhtml
<!-- xmlns etc. omitted -->
<html>
<f:metadata>
<f:viewParam name="userId" value="#{userPageController.userId}"/>
</f:metadata>
<f:view contentType="text/html">
<h:head>
</h:head>
<h:body>
<h:form>
<h:commandButton action="#{userPageController.doAction}" value="post"/>
</h:form>
</h:body>
</f:view>
userPageController.java
#Named
#ViewScoped
public class userPageControllerimplements Serializable {
private static final long serialVersionUID = 1L;
#Inject protected SessionController sessionController;
#Inject private SecurityContext securityContext;
#Inject protected UserDAO userDAO;
protected User user;
protected Long userId;
public UserPage() {
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
if(!FacesContext.getCurrentInstance().isPostback()){
User u = userDAO.find(userId);
this.userId = userId;
this.user = u;
}
}
public void doAction(){
}
}
However, after doAction is called, the view parameter in the url disappears. The bean still works due to its viewscoped nature, but it ruins my attempts of future navigation. When i search around, I get the impression that the view parameter should remain after a post thus reading userpage.jsf?userId=123, but this is not the case. What is really the intended behaviour?
Related to this, I've tried to implement automatic adding of view parameters when navigating to another page where I want to keep the userId. It seems to work for others, but for me, the userId in the ViewRoot is always null. Code below used to retrieve the viewparameter (i know i could use my temporarily stored userId in the bean for navigation, but this solution would be much fancier):
String name = "userId";
FacesContext ctx = FacesContext.getCurrentInstance();
ViewDeclarationLanguage vdl = ctx.getApplication().getViewHandler().getViewDeclarationLanguage(ctx, viewId);
ViewMetadata viewMetadata = vdl.getViewMetadata(ctx, viewId);
UIViewRoot viewRoot = viewMetadata.createMetadataView(ctx);
UIComponent metadataFacet = viewRoot.getFacet(UIViewRoot.METADATA_FACET_NAME);
// Looking for a view parameter with the specified name
UIViewParameter viewParam = null;
for (UIComponent child : metadataFacet.getChildren()) {
if (child instanceof UIViewParameter) {
UIViewParameter tempViewParam = (UIViewParameter) child;
if (name.equals(tempViewParam.getName())) {
viewParam = tempViewParam;
break;
}
}
}
if (viewParam == null) {
throw new FacesException("Unknown parameter: '" + name + "' for view: " + viewId);
}
// Getting the value
String value = viewParam.getStringValue(ctx); // This seems to ALWAYS be null.
One last thought is that the setter methods still seem to work, setUserId is called with the correct value on post.
Have I completly missunderstood how view parameters work, or is there some kind of bug here? I think my use case should be extremly common and have basic support in the framework.
When i search around, I get the impression that the view parameter should remain after a post thus reading userpage.jsf?userId=123, but this is not the case. What is really the intended behaviour?
This behaviour is correct. The <h:form> generates a HTML <form> element with an action URL without any view parameters. The POST request just submits to exactly that URL. If you intend to keep the view parameters in the URL, then there are basically 3 ways:
Bring in some ajax magic.
<h:commandButton action="#{userPageController.doAction}" value="post">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
This way the initially requested page and thus also the request URL in browser's address bar remains the same all the time.
If applicable (e.g. for page-to-page navigation), make it a GET request and use includeViewParams=true. You can use <h:link> and <h:button> for this:
<h:button outcome="nextview?includeViewParams=true" value="post" />
However, this has an EL security exploit in Mojarra versions older than 2.1.6. Make sure that you're using Mojarra 2.1.6 or newer. See also issue 2247.
Control the generation of action URL of <h:form> yourself. Provide a custom ViewHandler (just extend ViewHandlerWrapper) wherein you do the job in getActionURL().
public String getActionURL(FacesContext context, String viewId) {
String originalActionURL = super.getActionURL(context, viewId);
String newActionURL = includeViewParamsIfNecessary(context, originalActionURL);
return newActionURL;
}
To get it to run, register it in faces-config.xml as follows:
<application>
<view-handler>com.example.YourCustomViewHandler</view-handler>
</application>
This is also what OmniFaces <o:form> is doing. It supports an additional includeViewParams attribute which includes all view parameters in the form's action URL:
<o:form includeViewParams="true">
Update: obtaining the view parameters of the current view programmatically (which is basically your 2nd question) should be done as follows:
Collection<UIViewParameter> viewParams = ViewMetadata.getViewParameters(FacesContext.getCurrentInstance().getViewRoot());
for (UIViewParameter viewParam : viewParams) {
String name = viewParam.getName();
Object value = viewParam.getValue();
// ...
}
Am I right that for solution 1 <f:ajax execute="#form" render="#form" /> to work one would also have to include something like
<f:param name="userId" value="#{userPageController.userId}"/>
inside the <h:commandButton>?
Like it is described in https://stackoverflow.com/a/14026995/811046

commandbutton not executing action if other attributes are bind to managed bean

i'm really new to jsf.
I need to enable,disable, render or not render some buttons on a page depending on the logged user privileges. The page is bound to a request scoped managed bean , i bind the rendered or disabled attribute of the commandbutton to a "visible" property of the managed bean, and an actionlistener to a managedbean method which has the only purpose to navigate to another page.
If i bind one of the above properties to the visibile property, the navigation method doesn't get called, and the same page gets rerendered with the button disabled or not rendered.
The more urget need is the answer to "how do i disable or hide the button?" of course,
But , since i guess the problem is due to jsf page life cycle and the bean scope, i'd like also to be direct to some tutorial a bit more advanced than the hello world that can be found around.
below are part of the code.
Thank you in advance for any help
the xhtml page
<ui:define name="content">
<p:layoutUnit position="center" header="Dettaglio Pratica" scrollable="true">
<h:form id="formDettaglioPratica">
<!-- i've used javascript to redirect -->
<p:commandButton styleClass="commandButton" value="Modifica pratica" ajax="false"
rendered="#{praticaCtrl.visible}" onclick="navigateToChange();return false;"/>
<p:commandButton id="backButton" styleClass="commandButton" value="Torna alla lista"
onclick="navigateToHome();return false;"></p:commandButton>
<!-- never redirect to page defined in method checkIn -->
<p:commandButton id="checkinButton" styleClass="commandButton" value="Rilascia pratica" ajax="false"
actionListener="#{praticaCtrl.checkIn}" disabled="#{praticaCtrl.visible}"></p:commandButton>
<!-- printing output values -->
<h:inputHidden id="idPratica" value="#{praticaCtrl.idPratica}"></h:inputHidden>
<h:inputHidden id="idBox" value="#{praticaCtrl.box}"></h:inputHidden>
</h:form>
</p:layoutUnit>
</ui:define>
the relevant part of the managed bean
public boolean isVisible() {
return isVisible;
}
public void setVisible(boolean isVisible) {
this.isVisible = isVisible;
}
public void setUser(IUserProvider user) {
try{
if(pratica.getUtenteCheckOut() == null
|| (pratica.getUtenteCheckOut().getMatricola().equalsIgnoreCase(user.getUser().getMatricola()))
)
setVisible(true);
else
setVisible(false);
this.user = user;
}
catch(Exception ex)
{log.error(ex);}
}
public void checkIn(ActionEvent event)
{
try{
log.info(String.format("modifica della pratica %s", idPratica));
ajaxRedirect(String.format("../Box/ListaRichieste.xhtml?box=%s",box));
}
catch(Exception ex)
{
log.error(ex.getMessage(),ex);
}
}
this is the ajaxRedirect method,we don't use the navigation rules neither methods return string
protected void ajaxRedirect(String url) throws IOException {
FacesContext.getCurrentInstance().getExternalContext()
.redirect(url);
}
the answer for the described behaviour can be found at : http://forum.primefaces.org/viewtopic.php?f=3&t=13269&p=39996 ,which refers a BalusC answer on a similar question on stackoverflow : commandButton/commandLink/ajax action/listener method not invoked or input value not updated

Resources