Case is as follows:
you have a bean method which parses a file, and if parsing fail, error message is added, and if parsing successful, success message is added.
But when you make consecutive operations: fail > success , i expect that the fail message will disappear and the success message appears, but what happens is that fail message is still there, and success message is added to it.
Clearing the MessageList before adding the message is not a solution, because list is already cleared, if you try to print the message list size before adding the message in both cases it will be 0.
So what is the solution to remove fail message in case of success and vice versa?
Bean:
#Component("mybean")
#Scope("view")
public class MyBean {
try {
myservice.parseFile(file);
} catch (Exception e) {
FacesMessage msg = new FacesMessage();
msg.setSeverity(FacesMessage.SEVERITY_FATAL);
msg.setSummary("Invalid file.");
facesContext.addMessage(null, msg);
return;
}
FacesMessage msg = new FacesMessage();
msg.setSeverity(FacesMessage.SEVERITY_INFO);
msg.setSummary("Success");
facesContext.addMessage(null, msg);
}
View:
<h:form>
<ace:fileEntry id="fileEntryComp"
label="File Entry"
relativePath="uploaded"
fileEntryListener="#{mybean.listener}" />
<h:commandButton value="Upload File" />
<h:messages styleClass="myclass" infoStyle="Color:blue;" errorStyle="Color:red;" fatalStyle="margin-right: 85%; Color:red;" globalOnly="true"/>
<h:messages for="fileEntryComp" style="display:none;"/> <!-- to hide the faces development message-->
</h:form>
UPDATE:
i tried even the workaround here:
Is is possible to delete Component HTML Content with JSF
to clear the messages div before adding new messages, but no new, i don't know where he gets the old message from.
UPDATE2:
i even tried the two workaround mentioned here:
http://www.icefaces.org/JForum/posts/list/19753.page#71521
1- Adding context param:
<context-param>
<param-name>org.icefaces.messagePersistence</param-name>
<param-value>false</param-value>
</context-param>
doesn't work too.
2- Clearing saved global messages collection:
i tried this solution:
List<FacesMessage> globals = (List<FacesMessage>) facesContext.getViewRoot().getAttributes().get("org.icefaces.event.saved_global_faces_messages");
if (globals != null) {
globals.clear();
}
but i always get the following exception:
Caused by: java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.clear(Collections.java:1037)
at com.xeno.phoneSuite.beans.DepartmentBean.listener(DepartmentBean.java:176)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.el.parser.AstValue.invoke(AstValue.java:262)
at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
at org.icefaces.component.fileentry.FileEntry.broadcast(FileEntry.java:311)
... 92 more
finally, i tried the solution of the context param on the latest version ICEfaces 2.1 Beta 2 and it works fine:
<context-param>
<param-name>org.icefaces.messagePersistence</param-name>
<param-value>false</param-value>
</context-param>
http://wiki.icefaces.org/display/ICE/ICEfaces+2.1.0+Beta+2+Release+Notes#ICEfaces2.1.0Beta2ReleaseNotes-downloads
hope that will helps.
I am in Icefaces 3.3 and had a similar problem. I solved this using the following code (Oh BTW I also see that #BalusC has already pointed out such a solution in his comments):
Iterator<FacesMessage> msgIterator = FacesContext.getCurrentInstance().getMessages();
while (msgIterator.hasNext())
{
FacesMessage facesMessage = msgIterator.next();
msgIterator.remove();
}
Putting above piece of code before pushing a new message like this one, should clear your old message and replace it with the new message My Message:
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "My Message", null));
I struggled a lot and finally the fix was very simple whether it is prime faces or old faces, just add redisplay = false.
Below is the snippet of the code.
<p:messages id="globalMessages" global-only="true" redisplay="false">
<p:autoUpdate/>
</p:messages>
Related
for a university project we have to create a website using primefaces and spring boot.
My problem lies in the error handling. I have a p:dialog which lets you edit user information. Once you save the user, the dialog should close. However, if the save is not successful a error message should appear and the user-edit-dialog should stay open.
This is the commandButton which triggers the save:
<p:commandButton value="Save"
action="#{userDetailController.doSaveUser()}"
ajax="true"
validateClient="true"
oncomplete="if (args && args.closeForm) PF('userEditDialog').hide()"
update=":userForm:usersTable msgs mainPanel" />
As you can see it's an ajax request so for handling exception we use the integrated PrimeExceptionHandlerFactory.
<factory>
<exception-handler-factory>org.primefaces.application.exceptionhandler.PrimeExceptionHandlerFactory</exception-handler-factory>
</factory>
We are also displaying a dialog when a exception occurs.
<p:ajaxExceptionHandler type="at.qe.sepm.skeleton.utils.GeneralExpectedException" update="exceptionDialog"
onexception="PF('exceptionDialog').show();" />
<p:dialog id="exceptionDialog"
header="#{pfExceptionHandler.exception.type}"
widgetVar="exceptionDialog"
resizable="false">
Message: #{pfExceptionHandler.message}
<p:separator rendered="#{exceptionHelperBean.displayException(pfExceptionHandler.exception)}" />
<h:outputText rendered="#{exceptionHelperBean.displayException(pfExceptionHandler.exception)}"
value="#{pfExceptionHandler.formattedStackTrace}"
escape="false" />
</p:dialog>
My problem has to do with this line oncomplete="if (args && args.closeForm) PF('userEditDialog').hide()". The user-edit-dialog will only be closed when the closeForm flag is set. Which is done on the server:
PrimeFaces.current().ajax().addCallbackParam("closeForm", true);
From my understanding from other frameworks, when a exception occurs the server returns HTTP 500 and the onerror callback on the commandButton triggers.
Is there a more elegant way to do this? Ideally i don't want the oncomplete callback to trigger in the first place. I also tried using the onsuccess callback which doesn't get triggered at all, even if the request returns HTTP 200.
edit:
This is the doSaveUser methods inside the userDetailController:
public void doSaveUser() throws Exception {
user = this.userService.saveUser(user);
PrimeFaces.current().ajax().addCallbackParam("closeForm", true);
}
It internally calls the userServices save method where i manually throw the exception:
public User saveUser(User user) throws Exception {
if (user.isNew()) {
User existingUser = userRepository.findFirstByUsername(user.getUsername());
if(existingUser != null) {
throw new GeneralExpectedException("User with name " + user.getUsername() + " already exists",
ExceptionType.WARNING);
}
I hope this makes the problem more clear. Saving a user which already exists throws a exception - so the user edit dialog should stay open, in order to make adjustments. However, I also want the Exception dialog to trigger so you can see why saving is not possible.
Thank you for your help!
I'm creating a some sort of online shop with JSF. I have a product.xhtml page that displays the product by ID. I'm passing that ID as a param (.../product.xhtml?id=3) and I'm getting the ID with <ui:param name="productID" value="#{request.getParameter('id')}" />
That all works well.
Next, I'm showing and hiding certain elements in the page with <f:subview> (I've used <ui:fragment> before). The reason is that if the user deletes the ?id=3 ID parameter, the page will show an error (eg. code <f:subview id="main" rendered="#{productID != null and productID != ''}">). Another reason is that if the product belongs to the buyer, the BUY button will not appear and if the user is not authenticated the BUY button will not appear.
The problem is with the BUY button. It is in a form and the action of the button is just a simple test method (for now) from the CDI bean that prints something to the server console and redirects the user. Unfortunately, this does not work. The page (/product.xhtml) gets reloaded with no ID param.
I've tried several things like this and this and nothing is working.
I've tried using the ViewScoped and SessionScoped for my CDI bean instead of RequestScoped, but that does nothing. The ViewScoped fails to build.
I've also changed the <ui:fragment> to <f:subview>
Here's some code..
CDI bean controller
#Named
#RequestScoped
public class ProductManager {
...
public String buy(Product product) {
FacesContext context = FacesContext.getCurrentInstance();
try {
HttpSession session = Util.getSession();
User buyer = (User)session.getAttribute("user");
Date date = new Date();
System.out.println("TEST DATA: ");
System.out.println("sale product: "+product.getTitle());
System.out.println("sale buyer: "+buyer.getUsername());
System.out.println("sale date: "+date);
}
catch(Exception ex) {
System.err.println("ProductManager#buy -> "+ex.getMessage());
}
context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "An error occured", null));
return "index";
}
...
}
Products.xhtml
...
<ui:param name="productID" value="#{request.getParameter('id')}" />
...
<f:subview id="buyBtn" rendered="#{user.username != login.username and login.regUser}">
<h:form style="margin-top: 30px;">
<b:navCommandLink styleClass="btn btn-info btn-block" disabled="#{!product.status}" value="Buy" action="#{productManager.buy(product)}"></b:navCommandLink>
</h:form>
</f:subview>
...
I can provide full code if needed.
What I'm expecting the code to do is that whenever I click on the BUY button, I'll get redirected to my page and the TEST DATA will be printed on server console.
After many. many attempts I solved this. I cannot find the exact explanation, as I read a ton of articles on this topic.
I used OmniFaces. Next in products.xhtml I changed h:form to o:form (from OmniFaces) and have these two set to true includeRequestParams="true" includeViewParams="true". My bean then became org.omnifaces.cdi.ViewScoped
This is also a great article
I have to upload CSV file and I have to validate some values of file, for example does not allow negative value. Then, I need validate it and that file does not apear like "done" or "uploaded". I need handle an error on display it.
<rich:fileUpload
fileUploadListener="#{configClientBean.listener}"
ontyperejected="alert('some error');"
maxFilesQuantity="1"
onuploadcomplete="#{rich:component('waitPanelInterno')}.hide();"
onfilesubmit="#{rich:component('waitPanelInterno')}.show();"
render="pnlMensajes, idTableClients, scrollRegistros, outputPanelDetalle"
autoclear="true">
<rich:message for="uploadConfigClient" />
<a4j:ajax event="uploadcomplete" execute="popupFileLoad"
render="panelCarga, pnlMensajes" />
</rich:fileUpload>
In the Backing bean I can validate some things, but I cant show errors or change the behavior of "rich:fileUpload" compoment for example doneLable can not be displayed.
public void listener(FileUploadEvent event) throws Exception {
try {
UploadedFile file = event.getUploadedFile();
ByteArrayInputStream bais = new ByteArrayInputStream(file.getData());
InputStreamReader is = new InputStreamReader(bais, getMessage("iso"));
BufferedReader bufRead = new BufferedReader(is);
while ((registro = bufRead.readLine()) != null) {
if(cvsLine[1].isEmpty()){
// stop process
// Throw error
}
}
}
Thanks for your time.
To add extra behavior to the rich:fileUpload component that is not default is by creating your own file upload component (ex. myown:fileUpload) based on the rich:fileUpload source code and the use of the Component Development Kit.
A second solution could be by adding one extra message field that is described in this post: RichFaces fileupload and h:message problem
I'm using <p:fileUpload> which is restricted to PDF only. However, the invalidFileMessage shows inside the <p:fileUpload> component. How can I show it in <p:growl> instead?
<p:fileUpload allowTypes="/(\.|\/)(pdf)$/"
invalidFileMessage="File is Invalid. Only PDF files are allowed" />
You can't handle this server side. The file type is validated at client side without hitting any code in server side. So, any suggestions which suggest to manually create FacesMessage and/or explicitly add <p:message(s)> are unthoughtful and untested.
You should use jQuery. It solves everything.
Based on the fileupload.js source code, your best bet is to listen on the fictional show event of the message container and then move the messages container to end of the form.
First extend $.show() to actually trigger the show event.
(function($) {
var originalShowFunction = $.fn.show;
$.fn.show = function() {
this.trigger("show");
return originalShowFunction.apply(this, arguments);
};
})(jQuery);
Then simply create a listener on show event which basically runs when file upload messages appear and then parse every single message and use the renderMessage() function of the <p:growl> JS API. The below example assumes that you've a <p:growl widgetVar="growl"> somewhere in the same page.
$(document).on("show", ".ui-fileupload-content>.ui-messages", function() {
$(this).children().hide().find("li").each(function(index, message) {
var $message = $(message);
PF("growl").renderMessage({
summary: $(".ui-messages-error-summary", $message).text(),
detail: $(".ui-messages-error-detail", $message).text()
});
});
});
Well add an message tag in your page something like:
<p:messages id="test" autoUpdate="true" />
And in fileupload update="#this,test" and your message will be displayed in p:messages. You can change easly in growl works the same.
Look in the primefaces showcase for more examples
Looked up an example in Primefaces showcase and found this. The actual page:
<p:fileUpload fileUploadListener="#{fileUploadController.handleFileUpload}"
mode="advanced"
update="messages"
allowTypes="/(\.|\/)(pdf)$/"/>
<p:growl id="messages" showDetail="true"/>
And the file uploader controller class:
public void handleFileUpload(FileUploadEvent event) {
FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
Maybe something to keep in mind on how to display messages in Primefaces
I am trying to set an exception message in the <h:message>.
Here is the relevant view code:
<h:inputText id="titleId" value="#{bookController.book.title}"/>
<h:message for="titleId"/>
<h:commandButton value="Create a book" actionListener="#{bookController.doCreateBook}" action="listBooks"/>
I need a message to be displayed when the titleId is empty. My #Stateless EJB method throws an exception when the title is empty:
public Book createBook(Book book) throws CustomException {
if(book.getTitle().isEmpty()) {
throw new CustomException("Please, type a Title !");
}
else {
em.persist(book);
return book;
}
}
My backing bean catches it and sets a message:
public void doCreateBook() {
FacesContext ctx = FacesContext.getCurrentInstance();
try {
book = bookEJB.createBook(book);
bookList = bookEJB.findBooks();
} catch (CustomException e) {
ctx.addMessage("titleId", new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", e.getMessage()));
}
}
What I except is, when the exception occurs, an error message must be displayed near the input text tag, but it isn't the case, the execution displays the page with list of books and the "Error" message displayed under the list, as shown below:
How can I get the full exception message to show up next to the input field?
Apart from the erroneous message handling which Thinksteep has already answered, your other mistake is that you're doing validation in an action method. This is not right. You should be using JSF builtin validation facilities instead. Whenever the JSF builtin validation fails, then the action method will not be invoked and the page will also not navigate. The enduser sticks to the current form and the message will appear in the therefor specified <h:message> tag.
In your particular case, you just need to set the required attribute.
<h:inputText id="titleId" value="#{bookController.book.title}" required="true" />
<h:message for="titleId" />
If you want to customize the default required message, use requiredMessage attribute.
<h:inputText id="titleId" value="#{bookController.book.title}"
required="true" requiredMessage="Please, type a Title !" />
<h:message for="titleId" />
Remove that input validation from the EJB method. It doesn't belong there. The EJB isn't responsible for that, the caller (which is in your case thus your JSF code) is responsible for that.
ctx.addMessage("titleId", new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", e.getMessage()));
Your message text is Error and you are getting same. Change "Error" here to what ever you want.
PUT <h:messages showDetail="true" />