luni, 9 martie 2015

JSF 2.2 - <h:message> vs <h:messages>

The <h:message> and <h:messages> tags are used to display error messages when conversion or validation fails. More generally, in order to keep the end user informed about the success/failure of its actions (requests), JSF uses messages. There are four types of messages: Information, Warning, Error and Fatal, and each message can contain a summary and a detail (e.g. summary: Error!, detail: The provided address is not a valid e-mail!). Beside the JSF standard messages (standard error messages are provided with standard converters and standard validators in Messages.properties file - you can override these messages), JSF developers can write their own messages via FacesMessage:

FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
              "Error!", "The provided address is not a valid e-mail!");

Typically, the custom messages appear in custom converters and validators, but they also appear in managed beans or other JSF artifacts.
When multiple messages are associated with a client identifier (or with any specific component instance, if there is no client identifier), then the messages are added into a list of messages by using FacesContext.addMessage() method :

FacesContext context = FacesContext.getCurrentInstance();
//associated with any specific component instance (global)
context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
              "Error - global!", "The provided address is not a valid e-mail!"));
//associated with a client identifier (not global)
context.addMessage("clientId", new FacesMessage(FacesMessage.SEVERITY_ERROR,
              "Error - not global!", "The provided address is not a valid e-mail!"));

Note that client identifier is the component's clientId, NOT its id. Per example, in a table, each row has an unique clientId , but the same id, which means that the clientId allows us to attach a message to each row. Most commonly the clientId is composed as formId:componentId. This will attach the given message to:

<h:form id="formId">
 some component with ID, componentId
 <h:message for="componentId "> 
</h:form>

Now, the page author will use <h:message> and/or <h:messages> tags as placeholders for the messages. The <h:message> is used to render a single message for a specific component - the for attribute is mandatory and it points out the client identifier which benefits of this message. If more messages has been created for the same component, <h:message> shows only the first one:

<h:message for=" clientId" showSummary="true" showDetail="true"/>
Output: Error - not global! The provided address is not a valid e-mail!

By the other hand, <h:messages> is capable to display all messages in current page (including those displayed in a <h:message>). More technically, all messages stored in the faces context during the course of the JSF life cycle:

<h:messages showSummary="true" showDetail="true"/>
Output: Error - not global! The provided address is not a valid e-mail!
       Error - global! The provided address is not a valid e-mail!

Moreover, <h:messages> supports a flag attribute named, globalOnly which indicates that only global messages (that is, messages not associated with any client identifier) are to be displayed. Default value is false.

<h:messages globalOnly="true" showSummary="true" showDetail="true"/>
Output: Error - global! The provided address is not a valid e-mail!

Keep in mind that <h:messages> also support the for attribute, but this attribute is mutually exclusive with globalOnly and take precedence if used - <h:messages for="componentId"> can be used to show all messages attached to componentId. Starting with JSF 2.0, in Development stage, JSF  automatically attached a <h:messages> child to the current page. (the Mojarra 2.2 does this in RenderKitUtils.renderUnhandledMessages() method by creating an instance of the HtmlMessages component with id, javax_faces_developmentstage_messages). This is why you can see all messages without having an explicit <h:messages> or <h:message> in your page.

Typically, in validators, you will use something like this (maybe setting the component label is not so typical):
...
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Component label", "Validation error message"));
...

While in a converter will be more like this:
...
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Component label", "converter error message"));
...

Notice that, by default, JSF validation/converter error messages are prepared with the clientId of the component. They are not global messages.
A nice trick that I'd like to share involves the tooltip attribute of the <h:message> (also present in <h:messages>). If you set this attribute to true, and the showSummary to true and showDetail to false, then the detail will be wrapped in a tooltip that will appear when the mouse hovers over the summary:

<h:messages for="clientId" tooltip="true" showDetail="false" showSummary="true" />

OmniFaces spice up JSF messages with <o:messages> which is a component that extends the standard <h:messages> with the following new features: multiple for components, display single message, HTML escaping, iteration markup control. Moreover, OmniFaces utilities methods for messages provide really cool features.

Niciun comentariu:

Trimiteți un comentariu