How to Add HTML Code to Jsf Facesmessage

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:

  1. Use \n instead of <br> and apply CSS accordingly (easiest).

    #messages td { white-space: pre; }
  2. Create a custom renderer which extends MessageRenderer (bit harder, but nice if you want to cover more HTML than only linebreaks).

  3. 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.

  4. Or, when you're already on JSF 2.0, just iterate over FacesContext#getMessageList() yourself. Each item gives you a FacesMessage 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>
  5. Or, when you're using JSF utility library OmniFaces, use its <o:messages> component instead which has support for escape 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:

  1. 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 in faces-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 the encodeEnd() 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.

  2. Collect the messages in a List<FacesMessage> with help of FacesContext#getMessages() and just display them with help of c:forEach or t: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



Leave a reply



Submit