16
votes

In my screen, I have a drop down(select box), on selection of any of the options in that drop down , i display one or more text boxes beside the select box using javascript/css - display:none and display:block. All these input controls are in the same jsf form. Each of the input controls have their own validator. The problem is suppose the user selects option1 from selection box and doesn't input value or inputs a wrong value for inputbox1, i add a custom FacesMessage in the Validator and is shown appropriately and suppose the user selects the option2 the second time and inputs the wrong value for the inputbox2 then another FacesMessage is added in the validator. But Now both the Messages are shown - means - the message for inputbox1 and inputbox2 - which is wrong My assumption is that , this happens because they exist in the same form and their instances are not destroyed yet in the FacesContext and in the UIView. I decided to delete the messages this way

Iterator<FacesMessage> msgIterator = FacesContext.getCurrentInstance().getMessages();
    while(msgIterator.hasNext())
    {
        msgIterator.next();
        msgIterator.remove();
    }

But this sometimes gives java.util.NoSuchElementException org.apache.myfaces.shared_impl.renderkit.html.HtmlMessagesRendererBase$MessagesIterator.next

So 2 questions :

1) What is the problem in deleting the FacesMessages this way? I am using myfaces-api-1.2.3.jar and myfaces-impl-1.2.3.jar

2) Is there a better approach to handle my scenario? I only want to show relevent messages every time a jsf request is processed

Thanks

5

5 Answers

4
votes

As far as I can tell this is not enough, since in

org.apache.myfaces.context.servlet.FacesContextImpl

(version: 2.0.15, revision: 1364593), there are 2 lists of messages (_orderedMessages and _messages) and your method only clears _orderedMessages.

To clear _messages do this:

Iterator<String> itIds = FacesContext.getCurrentInstance().getClientIdsWithMessages();
while (itIds.hasNext()) {
    List<FacesMessage> messageList = FacesContext.getCurrentInstance().getMessageList(itIds.next());
    if (!messageList.isEmpty()) { // if empty, it will be unmodifiable and throw UnsupportedOperationException...
        messageList.clear();
    }
}

Please also note that this is very fragile since it relies on implementation details, but I could not find a better way :(

3
votes

The problem was not that I wasn't able to delete the messages from the FacesContext. The problem was that everytime the form was submitted there were few input controls (which were not displayed using display:none )which retained some values () and so the Validators and Backing Bean code added the FacesMessages for those non-visible input controls in the FacesContext. Now, everytime the select option was changed, i cleared the other form fields which were not necessary and so the messages are not added.

1
votes
FacesContext context = FacesContext.getCurrentInstance();
Iterator<FacesMessage> it = context.getMessages();
while ( it.hasNext() ) {
    it.next();
    it.remove();
}
1
votes

I don't use MyFaces, so I can't go in detail about this, but in the Sun RI (Mojarra) the bug of unremoveable facesmessages was been fixed in version 1.2_07 about 1.5 years ago.

So to achieve what you want, try upgrading MyFaces to the latest available (they might have fixed the same bug as well) or replacing by Mojarra.

-1
votes
if (FacesContext.getCurrentInstance().getMessages() != null) {
        FacesContext.getCurrentInstance().getMessages().remove();
    }