-
Available since OmniFaces 1.5
The <o:messages>
is a component that extends the standard <h:messages>
with the following new features:
Multiple for
components
Possibility to specify multiple client IDs space separated in the for
attribute. The example below would only display messages for input1
and input3
:
<h:form>
<o:messages for="input1 input3" />
<h:inputText id="input1" />
<h:inputText id="input2" />
<h:inputText id="input3" />
<h:inputText id="input4" />
</h:form>
It can even refer non-input components which in turn contains input components. The example below would only display messages for input1
and input2
:
<h:form>
<o:messages for="inputs" />
<h:panelGroup id="inputs">
<h:inputText id="input1" />
<h:inputText id="input2" />
</h:panelGroup>
<h:inputText id="input3" />
<h:inputText id="input4" />
</h:form>
You can even combine them. The example below would only display messages for input1
, input2
and input4
.
<h:form>
<o:messages for="inputs input4" />
<h:panelGroup id="inputs">
<h:inputText id="input1" />
<h:inputText id="input2" />
</h:panelGroup>
<h:inputText id="input3" />
<h:inputText id="input4" />
</h:form>
Displaying single message
Show a single custom message whenever the component has received any faces message. This is particularly useful when you want to display a global message in case any of the in for
specified components has a faces message. For example:
<o:messages for="form" message="There are validation errors. Please fix them." />
<h:form id="form">
<h:inputText id="input1" /><h:message for="input1" />
<h:inputText id="input2" /><h:message for="input2" />
<h:inputText id="input3" /><h:message for="input3" />
</h:form>
HTML escaping
Control HTML escaping by the escape
attribute.
<o:messages escape="false" />
Beware of potential XSS attack holes when user-controlled input is redisplayed through messages!
Iteration markup control
Control iteration markup fully by the var
attribute which sets the current FacesMessage
in the request scope and disables the default table/list rendering. For example,
<dl>
<o:messages var="message">
<dt>#{message.severity}</dt>
<dd title="#{message.detail}">#{message.summary}</dd>
</o:messages>
</dl>
Note: the iteration is by design completely stateless. It's therefore not recommended to nest form components inside the <o:messages>
component. It should be used for pure output only, like as the standard <h:messages>
. Plain output links are however no problem. Also note that the message
and escape
attributes have in this case no effect. With a single message, there's no point of iteration. As to escaping, just use <h:outputText escape="false">
the usual way.
Design notice
The component class is named OmniMessages
instead of Messages
to avoid confusion with the Messages
utility class.
Multiple for
components
Register one messages component for multiple input components.
Register one messages component for a specific group containing multiple input components.
Displaying single message
Show a single custom message whenever the component has received any faces message. Leave the inputs empty to see it.
Control HTML escaping
Default HTML escaping can be turned off by the new escape
attribute.
Control iteration markup
Control iteration markup fully by the new var
attribute which sets the current
FacesMessage
in the request scope and disables the default table/list rendering.
Admittedly, this was a bit poor example. The same layout could also be achieved with just
<o:messages>
without var
attribute.
It's just to give the general idea.
<h3>Multiple <code>for</code> components</h3>
<p>
Register one messages component for multiple input components.
</p>
<h:form id="form1">
<o:messages for="input1 input2" />
<h:panelGrid>
<h:inputText id="input1" required="true" />
<h:inputText id="input2" required="true" />
<h:panelGroup>
<h:inputText id="input3" required="true" />
<h:message for="input3" />
</h:panelGroup>
<h:commandButton value="Submit">
<f:ajax execute="@form" render="@form" />
</h:commandButton>
</h:panelGrid>
</h:form>
<p>
Register one messages component for a specific group containing multiple input components.
</p>
<h:form id="form2">
<o:messages for="inputs" />
<h:panelGrid>
<h:panelGroup id="inputs">
<h:inputText id="input1" required="true" />
<br/>
<h:inputText id="input2" required="true" />
</h:panelGroup>
<h:panelGroup>
<h:inputText id="input3" required="true" />
<h:message for="input3" />
</h:panelGroup>
<h:commandButton value="Submit">
<f:ajax execute="@form" render="@form" />
</h:commandButton>
</h:panelGrid>
</h:form>
<h3>Displaying single message</h3>
<p>
Show a single custom message whenever the component has received any faces message.
Leave the inputs empty to see it.
</p>
<h:form id="form3">
<o:messages for="form3" message="There are validation errors. Please fix them." />
<h:panelGrid columns="2">
<h:inputText id="input1" required="true" />
<h:message for="input1" />
<h:inputText id="input2" required="true" />
<h:message for="input2" />
<h:inputText id="input3" required="true" />
<h:message for="input3" />
<h:commandButton value="Submit">
<f:ajax execute="@form" render="@form" />
</h:commandButton>
<h:panelGroup />
</h:panelGrid>
</h:form>
<h3>Control HTML escaping</h3>
<p>
Default HTML escaping can be turned off by the new <code>escape</code> attribute.
</p>
<h:form id="form4">
<o:messages escape="false" />
<h:commandButton value="Show HTML message" action="#{messagesBean.showHtmlMessage}">
<f:ajax execute="@form" render="@form" />
</h:commandButton>
</h:form>
<h3>Control iteration markup</h3>
<p>
Control iteration markup fully by the new <code>var</code> attribute which sets the current
<code>FacesMessage</code> in the request scope and disables the default table/list rendering.
</p>
<h:form id="form5">
<ui:fragment rendered="#{not empty facesContext.messageList}">
<ul class="messages">
<o:messages var="message">
<li class="#{fn:toLowerCase(message.severity)}">#{message.summary}</li>
</o:messages>
</ul>
</ui:fragment>
<h:commandButton value="Show five random messages" action="#{messagesBean.showRandomMessages(5)}">
<f:ajax execute="@form" render="@form" />
</h:commandButton>
</h:form>
<p>
Admittedly, this was a bit poor example. The same layout could also be achieved with just
<code><o:messages></code> without <code>var</code> attribute.
It's just to give the general idea.
</p>
package org.omnifaces.showcase.components;
import java.util.Random;
import jakarta.enterprise.context.RequestScoped;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.application.FacesMessage.Severity;
import jakarta.inject.Named;
import org.omnifaces.util.Messages;
@Named
@RequestScoped
public class MessagesBean {
public void showHtmlMessage() {
Messages.addGlobalWarn("Beware of potential"
+ " <span style=\"background: yellow; border: 10px solid black; font-size: 1.5em;\">XSS attack holes</span>"
+ " when <span style=\"color: red; font-weight: bold;\">user-controlled</span> input is redisplayed through"
+ " messages! See also <a href=\"https://en.wikipedia.org/wiki/Cross-site_scripting\">Wikipedia</a>.");
}
public void showRandomMessages(int amount) {
Random random = new Random(System.nanoTime());
for (int i = 0; i < amount; i++) {
Severity severity = (Severity) FacesMessage.VALUES.get(random.nextInt(4));
String severityName = severity.toString().split("\\s")[0];
Messages.addGlobal(severity, "This is a global {0} message", severityName);
}
}
}