Getting the current global messages from FacesContext

cesaregb picture cesaregb · Sep 22, 2011 · Viewed 12.3k times · Source

I have a problem. I need to know whether my page has global errors or not. This is because I have 2 different h:messages (error containers)

<h:messages id="errorMsgsContainer"
layout="table" 
rendered="true"
styleClass="message-container error-message" 
infoClass="info" 
errorClass=" error" warnClass="warn-message warn" globalOnly="true"/>

<h:messages id="errorMsgsContainerValidation"
layout="table" 
styleClass="message-container error-message-validation" 
infoClass="info" 
errorClass="error" globalOnly="false"/>

One will show the business related messages and the other will just show the validation messages. There are two messages because of business requirements.

When validation error messages are produced, the facelet works fine, because one of the messages tag has the globalOnly="true" attribute-value pair.

The problem comes when I've a global-only error. It will appear in both boxes.

I want to know if any of there errors are global, so I don't show the validation container till the global errors are fixed by the user on my form.

I've tried to get it through the FacesContext with

FacesContext.getCurrentInstance().getMessageList().get(i).getSeverity()

and some other commands but it does not seem to work.

Please help me to solve this problem. How can I get the current global messages list, so I can know if there is any global error?

Answer

Vineet Reynolds picture Vineet Reynolds · Sep 22, 2011

When validation error messages are produced, the facelet works fine, because one of the messages tag has the globalOnly="true" attribute-value pair.

This is incorrect. You are seeing messages for validation errors, in the other h:messages tag with the globalOnly="false" attribute-value pair. Validation messages always have a client Id, which happens to be the Id of the form element that failed validation, and hence will be displayed in a messages tag that allows non-global messages to be displayed, or has the value of the for attribute set to the applicable Id.

The problem comes when I've a global-only error. It will appear in both boxes.

This is expected behavior. I believe you've confused the meaning of the globalOnly attribute. When the value of the globalOnly attribute is true, only global messages (i.e. messages without a client Id) will be displayed; when the value is false, global messages will be displayed in addition to other messages that are already queued. This would explain why global messages are displayed twice - the first h:messages tag would display the global message because it should display only global messages, and the second would display it because it can display it.

Please help me to solve this problem. How can I get the current global messages list, so I can know if there is any global error?

If you want to continue having two h:messages tags in your facelet, then you can use a "pseudo-global" Id when queuing your FacesMessages for display, instead of specifying an Id of null; the value of the pseudo-global Id in the following example is inputForm which is a valid client Id (of the form) that would not have any validation messages produced in this case:

FacesContext.getCurrentInstance().addMessage("inputForm", new FacesMessage(FacesMessage.SEVERITY_INFO, "Added a global message", null));

You can then add a EL expression to render the messages tag responsible for display of the input-validation messages:

<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"
      xmlns:fn="http://java.sun.com/jsp/jstl/functions">
...
    <h:form id="inputForm">
    ...
    </h:form>
    <h:messages id="psuedoGlobalMessages" for="inputForm" globalOnly="true" infoStyle="color:green" errorStyle="color:red" warnClass="color:orange" />
    <h:messages id="clientMessages" rendered="#{fn:length(facesContext.getMessageList('inputForm')) == 0}" globalOnly="false" infoStyle="color:green" errorStyle="color:red" warnClass="color:orange" />
...

Note, the use of the globalOnly attribute in only one messages tag. The same messages tag is also not displayed if a pseudo-global message is queued up for display via the EL expression specified in the rendered attribute. You can also use the client Id of a hidden form element created specifically to direct all pseudo-global messages, instead of the form's client Id.