How do I add HTML code to JSF FacesMessage
In theory, you want an escape
attribute for the h:messages
component like the h:outputText
has. You're not the only one who wants this, this is requested before more than often, but it's a WONTFIX according the JSF guys.
You have several options:
Use
\n
instead of<br>
and apply CSS accordingly (easiest).#messages td { white-space: pre; }
Create a custom renderer which extends
MessageRenderer
(bit harder, but nice if you want to cover more HTML than only linebreaks).Gather the messages yourself in some
List
in a bean and display them using<t:dataList>
, or when you're already using Facelets instead of JSP, using<ui:repeat>
. This way you can use<h:outputText escape="false">
to display the individual messages.Or, when you're already on JSF 2.0, just iterate over
FacesContext#getMessageList()
yourself. Each item gives you aFacesMessage
back which in turn offers several getters. You could then display the summary in a<h:outputText escape"false" />
.<ul>
<ui:repeat value="#{facesContext.messageList}" var="facesMessage">
<li>
<h:outputText value="#{facesMessage.summary}" escape="false" />
</li>
</ui:repeat>
</ul>Or, when you're using JSF utility library OmniFaces, use its
<o:messages>
component instead which has support forescape
attribute.<o:messages escape="false" />
Add html content to faces message from Backing Bean
Why not simply using h:messages tag ? It is fully customizable in terms of design and you can simply affect your styles and class without all the turn-around
Source : http://www.jsftoolbox.com/documentation/help/12-TagReference/html/h_messages.html
How can I add FacesMessage during page load? Using @PostConstruct does not seem to work
That can happen when the message component is rendered before the message is added.
In your specific example, the bean is referenced for the first time by the <h:outputText>
component and thus constructed for the first time at that moment. But the <h:outputText>
component appears in your specific example after the <p:messages>
component, so the <p:messages>
component is already rendered and thus it's too late to show the message.
You need to make sure somehow that the message is added before the message component is rendered. One way is using <f:viewAction>
. It runs during INVOKE_APPLICATION
phase which is before RENDER_RESPONSE
phase. Thus it runs before any component is rendered. A perfect opportunity thus.
<f:metadata>
<f:viewAction action="#{bean.onload}" />
</f:metadata>
public void onload() {
// Add message here instead of in @PostConstruct.
}
See also:
- What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Embedding a link (or other html) in a JSF message
Unfortunately, this is not possible in the standard JSF implementation. The component and the renderer doesn't officially support this attribute. You can however homegrow a renderer which handles this.
Since this is a pretty common requirement/wish, I thought to take a look what's all possible.
First some background information: JSF by default uses ResponseWriter#writeText()
to write the tag body, which escapes HTML by default. We'd like to let it use ResponseWriter#write()
instead like as with <h:outputText escape="false" />
. We'd like to extend the MessagesRenderer
of the standard JSF implementation and override the encodeEnd()
method accordingly. But since the MessagesRenderer#encodeEnd()
contains pretty a lot of code (~180 lines) which we prefer not to copypaste to just change one or two lines after all, I found it better to replace the ResponseWriter
with a custom implementation with help of ResponseWriterWrapper
wherein the writeText()
is been overriden to handle the escaping.
So, I ended up with this:
package com.example;
import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.context.ResponseWriterWrapper;
import javax.faces.render.FacesRenderer;
import com.sun.faces.renderkit.html_basic.MessagesRenderer;
@FacesRenderer(componentFamily="javax.faces.Messages", rendererType="javax.faces.Messages")
public class EscapableMessagesRenderer extends MessagesRenderer {
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
final ResponseWriter originalResponseWriter = context.getResponseWriter();
try {
context.setResponseWriter(new ResponseWriterWrapper() {
@Override
public ResponseWriter getWrapped() {
return originalResponseWriter;
}
@Override
public void writeText(Object text, UIComponent component, String property) throws IOException {
String string = String.valueOf(text);
String escape = (String) component.getAttributes().get("escape");
if (escape != null && !Boolean.valueOf(escape)) {
super.write(string);
} else {
super.writeText(string, component, property);
}
}
});
super.encodeEnd(context, component); // Now, render it!
} finally {
context.setResponseWriter(originalResponseWriter); // Restore original writer.
}
}
}
In spite of the @FacesRenderer
annotation, it get overriden by the default MessagesRenderer
implementation. I suspect here a bug, so I reported issue 1748. To get it to work anyway, we have to fall back to the faces-config.xml
:
<render-kit>
<renderer>
<component-family>javax.faces.Messages</component-family>
<renderer-type>javax.faces.Messages</renderer-type>
<renderer-class>com.example.EscapableMessagesRenderer</renderer-class>
</renderer>
</render-kit>
Then, to trigger it, just do:
<h:messages escape="false" />
And it works! :)
Note: the above affects <h:messages>
only. To do the same for <h:message>
, just do the same, but replace anywhere "Messages"
by "Message"
(component family, renderer type and classnames).
New Line character in FacesMessage Jsf
Without implementing a bizarre hack using javascript and css or without implementing your own JSF messages custom component this is not possible.
You will need to create a new FacesMessage for each line.
JSF - How can I format my global messages in <h:messages> in a visually appealing way?
After all, you want to change the HTML output. This really can't be done with CSS. CSS is more to give the existing HTML elements a layout, not to modify them. Apart from fiddling in JavaScript (which isn't easy in this particular case), you'd like to have JSF change its HTML output. There are basically two ways:
Supply your own
MessagesRenderer
so that it renders messages the way you want. Extend the base renderer class as used in MyFaces (sorry, since I don't use MyFaces I can't tell from top of head which class it is for MyFaces, you need to consult its API docs) and register it infaces-config
as follows:<render-kit>
<renderer>
<component-family>javax.faces.Messages</component-family>
<renderer-type>javax.faces.Messages</renderer-type>
<renderer-class>com.example.CustomMessagesRenderer</renderer-class>
</renderer>
</render-kit>Here,
com.example.CustomMessagesRenderer
is thus the custom renderer you've implemented. You'd like to override theencodeEnd()
method of the standard renderer to have it to output HTML the desired way. This is too much code to post as an example here, but just looking in the source code of the default messages renderer should give enough hints.Collect the messages in a
List<FacesMessage>
with help ofFacesContext#getMessages()
and just display them with help ofc:forEach
ort:dataList
and plain vanilla HTML. E.g.public List<FacesMessage> getMessages() {
List<FacesMessage> messages = new ArrayList<FacesMessage>();
Iterator<FacesMessage> iter = FacesContext.getCurrentInstance().getMessages();
while (iter.hasNext()) {
messages.add(iter.next());
}
return messages;
}with
<table border="1" id="myForm:messagesOutput" class="myMessagesTableClass">
<thead><tr><td>SUMMARY</td><td>DETAIL</td></tr></thead>
<tbody>
<c:forEach items="#{bean.messages}" var="message">
<c:set var="type" value="#{message.severity == 'SEVERITY_ERROR' ? 'error' : 'warn'}" />
<tr>
<td class="#{type}-message-summary"><span>#{message.summary}</span></td>
<td class="#{type}-message-detail"><span>#{message.detail}</span></td>
</tr>
</c:forEach>
</tbody>
</table>In JSF2, you'd have used
#{facesContext.messageList}
directly instead of#{bean.messages}
.
Passing a FacesMessage to the next page
Faces messages are indeed request scoped.
Just make use of the new JSF 2.0 Flash scope: Flash#setKeepMessages()
:
context.addMessage(clientId, message);
context.getExternalContext().getFlash().setKeepMessages(true);
// ...
This has only one caveat in the current Mojarra 2.1.13 release: the redirect has to take place in the same "folder" in the URL. This is fixed in the shortly upcoming 2.1.14. See also issue 2136.
Appearing of FacesMessage depends on markup sequence
You're doing the business job in a getter method which is in this particular example only invoked during producing the HTML output during render response phase. It's in this particular construct too late to add a faces message if the HTML representation of the messages component has already been produced beforehand. You cannot take back the already written bytes from the response.
In fact, you should never do business logic in getters. You didn't clearly state a concrete functional requirement anywhere, so it's hard to propose the right solution, but in this particular example, one of the solutions would be to perform the job in a pre render view listener method instead.
<f:view>
<f:event type="preRenderView" listener="#{testBean.init}" />
<h:messages id="error" globalOnly="true"/>
<h:outputText value="#{testBean.msg}"/>
</f:view>
with
private String msg;
public void init() {
msg = "getMsg";
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "getMsg"), null));
}
public String getMsg() { // Keep getter untouched! Don't do business logic in there!
return msg;
}
Update the above applies to JSF2 Facelets only. On legacy and deprecated JSP there's no similar way. Your best bet is then a getter returning an empty string and referencing it in top of the JSP.
<f:view>
<h:outputText value="#{testBean.initHack}" />
<h:messages id="error" globalOnly="true"/>
<h:outputText value="#{testBean.msg}"/>
</f:view>
with
private String msg;
public String getInitHack() {
msg = "getMsg";
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "getMsg"), null));
return "";
}
public String getMsg() { // Keep getter untouched! Don't do business logic in there!
return msg;
}
Unable to show faces message on xhtml page
I am not sure if it is your case. But if you redirect after generating the Messages, they are lost in the redirect process. You need to make sure there is no redirect in the faces config - or any other mean - in your page flow.
Related Topics
How to Change One Word Color of Placeholder
How to Pass Parameters to CSS Classes
Font Size with Percentage Value (%) Not Scaling with Screen Size
How to Get Rid of X and Up/Down Arrow Elements of a Input Date
Why Is Padding Expanding a Flex Item
Subpixel Anti-Aliased Text on HTML5's Canvas Element
:Before &&: After Pseudo Elements Not Showing Firefox
How to Make Text Vertically and Horizontally Center in an HTML Page
New Facebook Like Button HTML Validation
Does Http-Equiv="Refresh" Keep Referrer Info and Metadata
Encoding Ffmpeg to Mpeg-Dash - or Webm with Keyframe Clusters - for Mediasource API
How to Hide The Arrow That Is Displayed by Default on The HTML5 <Details> Element in Chrome
Integrating CSS Star Rating into an HTML Form
How to Prefix Ordered List Item Numbers with a Static String Using CSS