Extending the Messages Control: Multiple Messages for a Single Component
As you probably know, XPages has a built in mechanism for displaying Messages to the user. The options available to the developer are almost complete, but I believe there is one scenario not covered by the default ‘Messages’ controls. There is no way to show multiple messages for a single component. In this blog post I will show how this option can be made available by extending the default classes and modifying their behaviour.
The most common scenario you see these Messages used is when an Input Control fails conversion or validation.
These messages are part of JSF and are called ‘FacesMessages’. A FacesMessage can either be ‘Global’, which means it has no relation to any component in the component tree, or it can be a ‘Component’ message which is linked to a specific component.
You can create these messages yourself, either from Java using the FacesMessages class as such.
FacesMessage fm = new FacesMessage();
fm.setSummary("Invalid TPS Report Format");
fm.setDetail("We're putting cover sheets on all TPS reports from now on");
or from SSJS using some @ functions that are provided with the XPages Extension Library.
@ErrorMessage('A Global Error Message',null);
@ErrorMessage('An Error Message for a Component', 'yourComponentId');
@InfoMessage('A Global Info Message',null);
@InfoMessage('An Info Message for a Component', 'yourComponentId');
@WarningMessage('A Global Warning Message',null);
@WarningMessage('A Warning Message for a Component', 'yourComponentId');
To display these on an XPage we can use the <xp:message> or <xp:messages> control on an XPage.
- Use an <xp:message> control, which only allows you to show a single ‘Component’ message.
- Use an <xp:messages> control with the property globalOnly=false, which will show all the messages (Component and Global).
- Use an <xp:messages> control with the property globalOnly=true, this will show all the Global Messages.
- Use an <xp:messages> control that will show all the Component Messages for a single component.
What is the plan?
How can we make this option
- Create our own Messages Component which extends the existing one
- Set the renderer type to our new rendered (to be created) in the constructor of the component
- Add the ‘for’ property to the component.
- Implement State saving behaviour so that the ‘for’ property value is kept between requests
- Create the xsp-config file which describes the Component, extending the existing xsp-config for the built-in messages component and adding the for property
- Create our own renderer that extends the existing MessagesRenderer
- Override the getMessageIter function
- Register our new Renderer through FacesConfig
- Test our new component!
If you just want to see the end result, check out the project on GitHub.
Otherwise have a look at the following Code Walkthrough / Demonstration Video