XPages: Rendering Based on Error Messages

Home » XPages: Rendering Based on Error Messages

This is one of those occasions when I had written an article and was just waiting to get round to publish it, and another developer posted an article that covers a similar topic. Just this morning, Tommy Valand posted an article with some SSJS for accessing messages from the facesContext.getMessages and using an iterator to loop through and get the content, which is what I worked out how to do last week. Although there is some duplication on this aspect, this article does then add a bit of a gotcha when trying to use the Display Errors control to decide whether other controls should be rendered or not. Of course using a Computed Field control will get around the problem I encountered.

As a developer who comes to XPages from a standpoint of little or no Java knowledge, it is subjects like the facesContext object and iterators that push me outside of my comfort zone. The relative lack of Domino-focussed help on the topics makes it more challenging. I know there are plenty of Java resources on the web, but there can be subtle differences to the aspects of Java as implemented within SSJS. But not one to shrink from a challenge, now that I’ve got a good amount of experience in XPages, I’m tackling these areas, so hopefully my learning will be of benefit to other developers.

Recently I wrote an article about returning error messages from SSJS through the facesContext object. This can be useful if you want to avoid client-side validation, you want to put all your validation in a single save button but want to take advantage of the inbuilt Display Errors control. In that article I explained about creates new javax.faces.application.FacesMessage objects to add errors to the facesContext object (it’s not as hard as it sounds, believe me!).

Following on from that, I had the need last week in an XPages reporting panel to hide two date controls if certain reports were selected from a combobox. Sounds straightforward, and in normal circumstances it would be. Except the two controls in question were mandatory. I could compute a rendered property for the relevant controls, but by default they were mandatory. To set the rendered property to false I needed to do a partial refresh, recalculating the view model. Because I was developing for 8.5.1, this meant ensuring No Update and No Submission (refreshMode set to “partial” and submit set to “true”) and “Do not validate or update data” was unticked (immediate=”false”). But with these settings, the partial refresh would fail, because the two controls were currently mandatory. (Of course in 8.5.2 we have the option for “Process data without validation”, which gets round this whole problem.)

Various imaginitive solutions, like using CSJS to set values for the controls and subsequently clearing the values, proved fruitless. So I fell back on validating the relevant controls in SSJS instead and returning errors messages using the facesContext object. The step on from that is I needed to set a rendered property to false if nothing had been selected or there were errors currently returned. The former was easy: I was holding the selected report in a sessionScope variable, so could check that wasn’t blank (I am initialising it to a blank string in the beforePageLoad event). Checking for messages was slightly more difficult.

Again, my first point of reference was the facesContext object. That’s where I’m writing the messages to, that should be where I can get the messages from. A quick search on Java APIs and I was able to identify that what I needed was facesContext.getMessages(“messages1”), where messages1 was the Display Errors control I was writing the messages to. That then needed an Iterator object to cycle through the values. For those who have not used it before the Iterator object is another unfamiliar and uncomfortable element of SSJS, but again it’s very straightforward. The code I used was:

var it:Iterator=facesContext.getMessages(“messages1″);
var myMsg=””;
for (it; it.hasNext();) {
 myMsg += it.next().getSummary();
}
myMsg

The first line initialises the iterator to the list of error messages. The second line initialises a string for holding the error messages. Because I just want to know if there are any errors, I’m not concerned about the format of the return, I’m just going to check if it’s empty of nor. The for loop, again, is fairly straightforward, we’re just looping through the error messages, checking if there is a next error message, in which case getting it and using the getSummary() method. So how did I know to use the getSummary() method? Basically, I worked from the premise that it.getNext() got an instance of whatever was put into facesContext.getMessages(). I put something in there usin g facesContext.addMessage(), and the object I put in was a javax.faces.application.FacesMessage(). So I looked for the methods of that object, and worked out that getSummary() was the one to use.

Ok, so from there I had a string to identify if there were error messages. The obvious step would be to add a condition using this to the rendered property. Sounds straightforward. But that’s where I hit a brick wall. So I fell back to checking and logging progress through my code. If you don’t use error/event logging code in your SSJS, use it: it will save you a heap of trouble. In this case it told me the rendered property was being triggered multiple times for my partial refresh (five, I think). During each partial refresh I got three logs with myMsg as blank, then one log with a value in myMsg, then one log with myMsg as blank. I don’t know why it triggers the rendered property multiple times. Suffice to say, it does.

The solution was to put the iterator code into a Computed Field control with rendered set to false, and use that component when computing whether or not my table should be rendered. It’s a bit of a hack, admittedly. But it works.

But of course when 8.5.2 is rolled out I can just tick “Process data without validation”.

2 thoughts on “XPages: Rendering Based on Error Messages”

  1. Paul, you should be able to just bind rendered directly to facesContext.getMessages().hasNext(). If that expression returns true, at least one error has been reported (either a failed validation or some manual addition to the messages list).

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top