7
votes

I'm using JSF 2.0. I'm using the

<h:messages>

tag to render error messages. I can use css to style my messages a little bit but I've create a composite component to render messages that can be closed and adding effects to them with some Jquery.

I've seen tutorials on how to customize the messages, but most of these rely on css and customizing the text output yet what I want to do is generate specific markup, something like

<myComp:fancyMessage text="etcetcetc error msg" type="error" />

instead of the regular message markup. Is this possible?

EDIT:

I don't want to style up jsf messages. Neither add background nor change its style, but rather create my own message html markup. Here:

http://balusc.blogspot.com/2010/07/using-html-in-jsf-messages.html

I've found how to add html to your messages. What I want is to encapsule all the html in my composite component, and then just use my composite component in this way:

<mycomp:messages/>

or

<mycomp:message for="componentID" />

where message and messages both create their own html markup

3
Your question is very vague. You said that you've created a composite component with some jQuery and then you're asking if it is possible to create a custom (composite) component. What is the concrete problem/question?BalusC
@BalusC I was just reading your blog and stumbled upon this: balusc.blogspot.com/2010/07/using-html-in-jsf-messages.html which is not exactly what I'm looking for. I missed that entry.arg20
I apologize for my question being so vague. I meant i created a composite component to display messages. I need jsf to render messages using that composite component.arg20
I don't want the html markup to be in the message but rather in the component.arg20
Ah yes, I now understand what you mean.BalusC

3 Answers

13
votes

Use FacesContext#getMessageList() inside ui:repeat. Each item is a FacesMessage which has several getters.

<ui:repeat value="#{facesContext.messageList}" var="facesMessage">
    Severity: #{facesMessage.severity}<br />
    Summary: #{facesMessage.summary}<br />
    Detail: #{facesMessage.detail}<br />
    <br />
</ui:repeat>

This allows for more fine-grained HTML markup around the messages.


And it also enables you to print them as HTML with help of <h:outputText escape="false">. I might need to expand and revise my blog article sooner or later :)

3
votes

In reply to how to set your component as message renderer:

Your component needs to extend HtmlBasicRenderer.

Then you can add your renderer to faces-config.xml

<render-kit>
    <renderer>
        <component-family>javax.faces.Messages</component-family>
        <renderer-type>javax.faces.Messages</renderer-type>
        <renderer-class>com.mypackage.MessagesRenderer</renderer-class>
    </renderer>
</render-kit>
1
votes

I know it's been a while, but thought to share this alternate solution for the benefit of others. For composites, create a backing component with a getter, then iterate over the faces messages and call remove() after collecting each message. This will get you around the "messages queued" warning without the h:messages hack.

xhtml:

<composite:interface displayName="Messages Component"
    shortDescription="Messages Component" componentType="com.company.dept.commons.ui.messages.Messages">
    <composite:attribute name="styleClass" default="" type="java.lang.String" shortDescription="CSS style class for the component" />
</composite:interface>

<composite:implementation>
    <div id="messagesComponent" class="#{cc.attrs.styleClass}">
        <ui:repeat value="#{cc.messageList}" var="message">
            #{message.severity} - #{message.detail}<br/>            
        </ui:repeat>
    </div>
</composite:implementation>

Backing component:

@FacesComponent("com.company.dept.commons.ui.messages.Messages")
public class Messages extends UINamingContainer {

    private List<FacesMessage> messages;

    public List<FacesMessage> getMessageList() {
        //preserve messages in case getter is called multiple times
        if (messages == null) {
            messages = new ArrayList<FacesMessage>();
        }

        Iterator<FacesMessage> messageItr = getFacesContext().getMessages();
        while(messageItr.hasNext()) {
            FacesMessage message = messageItr.next();
            messages.add(message);
            messageItr.remove();
        }
        return messages;
    }       
}

Note the componentType in the xhtml is set to the FacesComponent value in the code. Also, the reference to cc.messageList will trigger the call to getMessageList().

Hope this helps.