Friday, 29 May 2015

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.setSeverity(FacesMessage.SEVERITY_ERROR);
fm.setSummary("Invalid TPS Report Format");  
fm.setDetail("We're putting cover sheets on all TPS reports from now on");

FacesContext.getCurrentInstance().addMessage("someClientId", fm);

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.

The options available to the developer for displaying messages using the standard XPages controls are:
  • 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.
Sometimes though I want the following option which is not available!
  • Use an <xp:messages> control that will show all the Component Messages for a single component.
There is currently no way to do this, the only messages control that is linked to a component is the <xp:message> control, and it only will show 1 message. Even if you have created more than one Component message for that control, it will still only show the first.

What is the plan?

My plan is to take the current messages control, and make it render multiple messages exactly as it does so already, however I want to control the list of messages that it renders. Instead of the list being 'All Messages' or 'Global Messages', I am going to add a new 'for' property in which I can specify which component id the messages should be for. If this 'for' property is blank, then the id of the messages control itself will be used instead.

How can we make this option

It turns out that doing it does not take too much work, but knowing what steps to take is the hard part.
Here are the steps will we take
  1. Create our own Messages Component which extends the existing one
    1. Set the renderer type to our new rendered (to be created) in the constructor of the component
    2. Add the 'for' property to the component.
    3. Implement State saving behaviour so that the 'for' property value is kept between requests
    4. 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
  2. Create our own renderer that extends the existing MessagesRenderer
    1. Override the getMessageIter function
    2. Register our new Renderer through FacesConfig
  3. Test our new component!
If you just want to see the end result, check out the project on GitHub.
camac/XPagesMessagesControl
Otherwise have a look at the following Code Walkthrough / Demonstration Video





6 comments:

  1. You must not have gotten the memo about the new TPS Report cover sheets

    ReplyDelete
    Replies
    1. :)
      or I could have used
      @ErrorMessage("PC LOAD LETTER",null);

      Delete
  2. Hi, I've managed to use this control on one of my app. It's very good and I've used it extensively. It's becoming that I've preferred this over the other 2 error messages control supplied by default with domino designer. However there's 1 quirk which is if I just opened the app in designer, once designer finished loading it, the eclipse Problems view will show "The unknown tag gb:messages cannot be used as a control.". If I opened any XPages or any CC that used this control, the Messages control won't even appear in the list of controls. The error will only go away after I clean the app. And then the control will appear under the list of controls. Is there any other way you can make this a permanent custom control that I can install in the Domino Server?

    ReplyDelete
    Replies
    1. Sorry for the delayed response I have been very busy lately!

      I'm glad to hear that it has been useful! It is really nice to hear that it is being used.

      Yes, the 'unknown tag' problem is very annoying when developing controls within the NSF.

      In response to your comment I have just made an update to the project and released it as an XspLibrary. You can download it on the releases page at the following link:

      https://github.com/camac/XPagesMessagesControl/releases/tag/v1.0.0

      Delete
    2. Ok, I've donwloaded it, installed it to both Domino Server and Designer and tested everything. It's working perfectly and without that error now.

      Thanks again for this despite your busy schedule! :-)

      Delete
    3. No worries glad to hear it worked!

      Delete