How to solve "p:message not working" in Primefaces? - java

I'm building a form that let the user enter database connection parameters. Once the parameters are typed
the user can test (btnTester) if connection can be established with its parameters.
In all cases, a message is produced for the user. Here the example of a failed connection attempt from backing bean code :
(...)
addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Connection failed.", t.getLocalizedMessage()));
(...)
Here is the form code. I'd like the message to appear in a p:message. Unfortunately, nothing happen. No message (connection successful or not) is displayed after the button :\
Even with the global attribute set to false or true.
<h:form prependId="false">
(...)
<h:panelGrid>
<!-- Other form components here -->
<f:facet name="footer">
<p:commandButton
id="btnTester"
value="Tester"
actionListener="#{assistantCreationSourcesBean.testerConnexionBase}"
update="msgTester" />
<p:message id="msgTester" for="btnTester" />
</f:facet>
</h:panelGrid>
</h:form>
What am I missing ?

You are missing an update attribute on your <p:commandButton> that specifies the ID of the <p:message> component to update.
You should give the message component and ID and specify it in update of the commandButton.

I think your problem is here:
addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Connection failed.", t.getLocalizedMessage()));
I'm assuming that you're calling FacesContext.addMessage(). That first parameter is the component id string. If you set it to null, then you force the message to be a global message. The <p:message> component you have defined is set to for="btnTester" so it will only display messages with a component id that matches the id of your btnTester component.
Except from the Javadoc for addMessage():
Append a FacesMessage to the set of messages associated with the specified client identifier, if clientId is not null. If clientId is null, this FacesMessage is assumed to not be associated with any specific component instance.
Link to FacesMessage Javadoc for addMessage() method

I use a growl instead of a message for solving my problem.

Found a solution that works Perfectly with message in Prime face.
Thought Sharing with you even if u worked it out with growl
Here is the solution
The add addMessage has 2 parameters, a UIComponent Client Id and FacesMessage. The facesMessage shows or defines the message and Component Child Id shows where the component is.
Here you have missed the Component Part.
In-order to make it work you should bind the UIComponent with the bean class.
So that it can find the Component .
Now do as follows,
Define a UIComponent in bean class
Bind it with the corresponding command Button
and get the Id From the component in the bean Class
Your Code must be changed like this
> private UIComponent component;
(...)
addMessage(component.getClientId(), new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Connection failed.", t.getLocalizedMessage()));
(...)
Inside the xhtml file you must bind the UIComponent
<h:form prependId="false">
(...)
<h:panelGrid>
<!-- Other form components here -->
<f:facet name="footer">
<p:commandButton
id="btnTester"
value="Tester"
actionListener="#{assistantCreationSourcesBean.testerConnexionBase}"
update="msgTester"
binding="#{assistantCreationSourcesBean.component}"/>
<p:message id="msgTester" for="btnTester" />
</f:facet>
</h:panelGrid>
</h:form>
Now the message will work..!! For me it worked perfectly :)

Here "for" attribute won't work for p:message use p:messages instead.
<p:messages id="txtname" showIcon="false"
showDetail="true" showSummary="false"
redisplay="false" for="someKey" display="text"/>

My guess is that you try to update a component that not yet being render. Try this
Use Firefox Firebug and check the html source to see if component id msgTester exist. If it is not then it explain why your update wont work. You cant update something that it is not there. How to fix this, well you can create a wrapper for this, and update your wrapper. Your wrapper should be something that it is always there, like h:form. IF you dont want to update the whole form, then you can try <p:outputPanel id="wrapper">. so your code would look like this
<h:form>
...
<p:outputPanel id="wrapper">
<p:commandButton ... update="wrapper"/>
<p:message />
</p:outputPanel>
</h:form>
try this and let me know if it work.

I have encountered this problem recently with PrimeFaces 6.0.19.
It turns out that I must have to call FacesContext.getCurrentInstance().validationFailed() before I call the addMessage() method so the message can be properly shown.
i.e.
FacesContext.getCurrentInstance().validationFailed();
//if you set the client ID to be null, you should add globalOnly=true in <p:messages>
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Connection failed.", t.getLocalizedMessage()));

Related

Message is not shown on ajax update

I've read dozens of question regarding similar problem, but could not find an answer to it. I've got this piece of code inside a form:
<p:outputPanel id="articleInfo">
<p:growl id="messages" autoUpdate="true"/>
<p:panel rendered="#{not empty myBB.selectedProduct}">
<p:panel>
<h:outputText escape="false" value="#{myBB.content}"/>
</p:panel>
<p:commandButton value="Button" update=":mainForm:articleInfo"/>
</p:panel>
</p:panel>
When I click a button, new content is generated in the backing bean and FacesMessage is added like this:
public String getContent(){
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(severity, title, detail));
return "something";
}
The ajax update is fine because I see new content, addMessage is also called, but I cannot see the message. I've tried p:messages instead of growl, adding for="mainForm:articleInfo" and calling the addMessage with "mainForm:articleInfo" (I've checked that it's the correct ID in the view.
I still cannot find a reason for this.
The reason your messages are not displayed because you've added the code to add message in a getter which is not ideal.
Why getter gets called multiple times
Remove the adding message code and put inside a method which gets called on some action.

Failed validation during AJAX form submission breaks AJAX

Okay, so I have read through stackoverflow and various other portions of the net for a few days, and have not found a solution yet that fixes my issue.
Basically, I have an h:form in a p:dialog with two required fields. When the fields are both filled in, the form successfully submits and the dialog closes. When either or both fields are left blank, required field validation fails and updates the h:messages component in the p:dialog with the appropriate required messages. However, also when validation fails, the AJAX call seems to never "finish" and prevents subsequent calls from being executed. This is seen evident by my p:ajaxStatus component never disappearing from the screen, indicating that something is hanging somewhere. This is remedied by refreshing the page, at which point all other AJAX components begin to function again.
Additionally, I will note that this p:dialog is in a ui:define in a ui:composition, that dumps it into a master template. It is not nested within another h:form.
<p:dialog id="dlgDecision"
header="Decision"
widgetVar="dialogDecision"
modal="false"
resizable="false"
appendToBody="true">
<h:form id="fDlgDecision">
<h:messages id="msgDlgDecision" binding="#{msgform.messages}" errorClass="errormsg" infoClass="infomsg1" layout="table"/>
<h:outputFormat rendered="#{studentdetailsform.decisionAction == 'A'}">
<h:outputText value="Select an accept and admit code."/>
</h:outputFormat>
<h:outputFormat rendered="#{studentdetailsform.decisionAction == 'C'}">
<h:outputText value="Select a cancel and reason code."/>
</h:outputFormat>
<h:panelGrid columns="1">
<h:selectOneMenu id="apdcCode"
value="#{studentDetails.apdcCode}"
required="true"
requiredMessage="Please choose a decision code.">
<f:selectItem itemLabel="Select Decision Code"/>
<f:selectItems value="#{apdcCodes.apdcCodeList}"
var="apdc"
itemValue="#{apdc.apdcCode}"
itemLabel="#{apdc.apdcCode} - #{apdc.apdcDesc}"/>
</h:selectOneMenu>
<h:selectOneMenu id="admtCode"
value="#{studentDetails.admtCode}"
required="#{studentdetailsform.decisionAction == 'A'}"
requiredMessage="Please choose an admit code."
rendered="#{studentdetailsform.decisionAction == 'A'}">
<f:selectItem itemLabel="Select Admit Code"/>
<f:selectItems value="#{admtCodes.admtCodeList}"
var="admt"
itemValue="#{admt.admtCode}}"
itemLabel="#{admt.admtCode} - #{admt.admtDesc}"/>
</h:selectOneMenu>
<h:selectOneMenu id="wrsnCode"
value="#{studentDetails.wrsnCode}"
required="#{studentdetailsform.decisionAction == 'C'}"
requiredMessage="Please choose a reason code."
rendered="#{studentdetailsform.decisionAction == 'C'}">
<f:selectItem itemLabel="Select Reason Code"/>
<f:selectItems value="#{wrsnCodes.wrsnCodeList}"
var="wrsn"
itemValue="#{wrsn.wrsnCode}"
itemLabel="#{wrsn.wrsnCode} - #{wrsn.wrsnDesc}"/>
</h:selectOneMenu>
<p:commandButton id="decisionSubmit"
value="Submit Decision"
type="submit"
action="#{mainform.saveDecision}"
ajax="true"
partialSubmit="true"
process="#form"
update="#form msgDlgDecision"
oncomplete="if (!args.validationFailed) dialogDecision.hide()"/>
</h:panelGrid>
</h:form>
</p:dialog>
Some things I have already done in my debugging and troubleshooting:
- Moved the h:form into the p:dialog
- Made the backing bean with the values for the rendered attribute on the required fields ViewScoped (was having an issue with only some of the required messages showing, this resolved this problem)
- Added appendToBody="true" to p:dialog
- Added if (!args.validationFailed) to the oncomplete event of p:dialog
- Tried making the required fields NOT conditional (removed rendered attributes) to be sure this wasn't being caused by failed validation on non-rendered components (grasping at straws...)
EDIT: Here is a console dump from Chrome. Javascript error gets thrown when submitting the form with null required fields.
Uncaught SyntaxError: Unexpected token { jquery.js:14
bG.extend.parseJSON jquery.js:14
PrimeFaces.ajax.AjaxUtils.handleResponse primefaces.js:1
PrimeFaces.ajax.AjaxResponse primefaces.js:1
j.success primefaces.js:1
bZ jquery.js:14
b7.fireWith jquery.js:14
ca jquery.js:21
bZ
EDIT 2: Below are the only two JavaScript imports, both of which are in my template that is applied to the page via the ui:define and ui:composition mentioned above.
<h:outputScript library="primefaces" name="jquery/jquery.js" />
<script type="text/javascript" src="#{request.contextPath}/resources/scripts/jscript.js" />
The first import will force Primefaces to import jQuery into the page, even if there are no components on the page that utilize JavaScript. This is to allow my custom scripts in jscript.js to use jQuery reliably.
Other information:
JSF 2.1
Primefaces 3.4.2
Tomcat 6.0
Don't import jQuery.js manually as this is already done implicitly by PrimeFaces (it uses jQuery under the hood). You can remove that line.
Also you should see some examples of importing your custom js files with h:outputScript like this for example:
<h:outputScript library="scripts" name="jscript.js" />
but this is probably not reason of your problem, this is just hint for better JSF design.
A similar error showed up in Google Chrome, today, after I downloaded PrimeFaces 4.0 snapshot (2013-05-09) and tested my app.
Basically, I had to remove single quotes from data sent from bean to p:schedule via JSON. Since the error mentioned 'parse JSON' and "unexpected '" (unexpected single quote), I went to the datatable view of my data (instead of p:schedule) and recognized that some of the data had single quotes embedded. So, I removed the single quotes from the data, and that solved the issue for me.
Please click forum topic URL below.
PF 4.0 SNAPSHOT 2013-05-09: schedule not working
I've had the exact same problem at my application. The real problem was a duplicate jar problem.
I've had two primefaces jar in my application, one under the WEB-INF/lib directory, and the other under the ear/lib directory. Once I deleted the one under the WEB-INF, everything started to work as expected.
You could find the solution on the net via a search for the js exception.

Ajax callback onstart works even if input is invalid

I have input fields and a command button inside an <h:form>. The input fields are required, and the validation error messages are showing well if something invalid is entered. At the end of the form, I have the following button:
<p:commandButton value="" ajax="true" update="foormm"
icon="ui-icon-check" actionListener="#{bean.sayHello}"
onstart="dialog.show()"
oncomplete="handleAjaxResponse(xhr, status, args)">
</p:commandButton>
The problem is, the dialog is showing regardless of validation. I thought the Ajax request was made iff inputs are validated. What's wrong here? Why does onstart get triggered even though the required fields are empty?
I use JSF 2.0, Primefaces 3.0 and Weblogic 12.1 with Eclipse.
Any help appreciated.
In other words, you want to show the dialog only when no validation errors have occurred after the postback? The onstart doesn't take that into account at all. It's invoked right before the ajax postback is invoked.
You'd need to approach it differently. The <p:dialog> has a visible attribute which can take an EL expression evaluating to a boolean outcome. You could make use of it:
<p:dialog id="dialog" visible="#{some condition}">
The #{some condition} can at its simplest be a combination of FacesContext#isPostback() and FacesContext#isValidationFalied(). So, if it's a postback and the validation has not failed, then the dialog should be visible.
<p:dialog id="dialog" visible="#{facesContext.postback and not facesContext.validationFailed}">
You just have to let your button update that dialog as well:
<p:commandButton value="" ajax="true" update="foormm dialog"
icon="ui-icon-check" actionListener="#{bean.sayHello}"
oncomplete="handleAjaxResponse(xhr, status, args)">
</p:commandButton>
Alternatively, you can also let the dialog's visible condition depend on some bean property which you set in the action(listener?) method:
<p:dialog id="dialog" visible="#{bean.saidHello}">

Is there a way to not sending a whole web form when click a button?

I will try to be as brief as possible, please stay with me here
"A.jsf" -> managed bean : bean
"#{bean.list}": will take us to B.jsf
<p:growl id="msgs" showDetail="true"/>
<h:form id="myform1" enctype="multipart/form-data">
<p:panel header="Upload" style="font-size: 11px;">
<h:panelGrid columns="2" cellpadding="10">
<h:outputLabel value="Drawing:" />
<p:fileUpload fileUploadListener="#{bean.handleFileUpload}" update="msgs" allowTypes="*.*;"/>
</h:panelGrid>
<p:commandButton ajax="false" immediate="true" id="back" value="Back" action="#{bean.list}"/>
<p:commandButton ajax="false" id="persist" value="Persist" action="#{bean.handleRevision}" />
</p:panel>
</h:form>
Then the handleFileUpload()
if(!upload){
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "You do not have permission to upload.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
...
"B.jsf" -> managed bean: bean2
...
<p:growl id="msgs" showDetail="true"/>
...
When I click upload, it give me a growl error message "You do not have permission to upload.", which is good. But then when I click "Back", which will take me to B.jsf, I see the growl message "You do not have permission to upload." again. What seem to be happening is as I click the "Back", I send other form request to upload, which then generated the same error message, which then being displayed at B.jsf. Is there a way to fix this, beside putting the "Back" button into an empty form, because now I have two buttons standing on top of each others, instead of side by side. I try to do this:
FacesContext.getCurrentInstance().addMessage("tom", msg);
hoping that it would send to component with id="tom", so then the growl with id=msgs, would not get load, but no luck. I try to turn the upload flag on when I click the Back button, but the web form get requested before the method that handle the back navigation get called.
It is not as brief as I want it to be, therefore I want apologize for it :D
beside putting the "Back" button into an empty form, because now I have two buttons standing on top of each others
The HTML <form> is by default a block element. HTML block elements are by default been placed in a new line. You actually want to make it an inline element. You can do this using display: inline; in CSS.
Back to the actual problem, it however surprises me that the fileUploadListener method is called in spite of the immediate="true" in the p:commandButton. I tried to reproduce this and I can confirm this. But I wouldn't expect it to happen. Normally the immediate="true" on a button is the solution to skip submitting of the "whole" form (at least, skip the UIInput components without this attribute). Further investigation learnt me that the p:fileUpload isn't an UIInput component at all and that the listener is fired during apply request values phase instead of validations or update model values phase. So this behaviour is fully predictable, but imo still an oversight in the design.
Since the p:fileUpload requires ajax="false" on the p:commandButton component, you can on the other hand also just remove it from the back button so that it fires an ajaxical request and hereby skips the fileUploadListener being called.
Actually, putting the button in a different form sounds like an excellent solution. The reason the buttons don't align any more is that the new starting <form> element starts on its own line. You should be able to prevent this by adding form { display: inline; } to your CSS file.
That said, if you have some leftover error messages that you want to get rid of, you can do this in the initializing method of your backing bean (if you have one). The following works peachily:
public void clearErrorMessages() {
//it may get messy to debug why messages are swallowed
logger.debug("clearing messages, coming from " + new Exception().getStackTrace()[1]);
Iterator iter = FacesContext.getCurrentInstance().getMessages();
while (iter.hasNext()) {
FacesMessage msg = (FacesMessage) iter.next();
logger.debug("clearing message: " + msg.getDetail());
iter.remove();
}
}
The disadvantage here is that any errors that occur between submitting the form and initializing the backing bean of the target page are also swallowed.

Call rich:modalPanel for every ajax request with out using a4j:status?

I am developing web application using JSF richfaces.I have one rich:modalpanel in main templete. This modalPanel have 'Your request is processing....." message.
I want to show this message(modalPanel) every action(ajax request). But without using a4j:status element.
Is there possible to acheive this(using listener or any otherway)?
How to show the wait modalPanel for all action using listener?
Help me about this.
Thanks in advance.
Update :
If i use my main templete,
<a4j:status id="waittingMessage"
onstart="javascript:Richfaces.showModalPanel('progressWaitModalPanel');"
onstop="javascript:Richfaces.hideModalPanel('progressWaitModalPanel');"/>
And i call the above a4j:status for the following places :
The following each and every component i use more than 100 place in my application
<a4j:commandButton status="waittingMessage"/>
<a4j:commandLink status="waittingMessage"/>
<h:selectOneMenu><a4j:support status="waittingMessage"/> </h:selectOneMenu>
<h:selectOneRadio><a4j:support status="waittingmessage"/></h:selectOneRadio>
<h:selectBooleanCheckbox><a4j:support status="waittingmessage"/></h:selectBooleanCheckbox>
In future,
i don't need to show the progressWaitModalPanel, that time i will delete a4j:status
in main templete.
But what about this status="waittingMessage"? Because this status="waittingmessage" i added more than 1000 places in my whole application.
<a4j:status> is the proper way to do this. I don't know of any other way. Perhaps you can hook to some low-level javascript, but that would be the wrong thing to do.
If the status is in the current form, there is no need to explicitly indicate which is the status - it is used by default.
<a4j:status id="waittingMessage"
onstart="Richfaces.showModalPanel('id_modalPanel')"
onstop="Richfaces.hideModalPanel('id_modalPanel')">
<f:facet name="start">
<label></label>
</f:facet>
<f:facet name="stop">
<label></label>
</f:facet>
</a4j:status>
<ui:include src="/modalPanel.xhtml" />
modalPanel.xhtml can contain display related content.
you can put the content above in a separate file say status.xhtml and then include it in your other pages
as below:
<a4j:outputPanel ajaxRendered="true">
<ui:include src="status.xhtml" />
</a4j:outputPanel>
so any page that has ajax request will display above message window
You need not add any status msg for each a4j:button ,etc.

Categories